﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Область СлужебныйПрограммныйИнтерфейс

Функция СхемаКомпоновкиДанныхИзТаблицыЗначений(ТаблицаЗначений) Экспорт
	
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
	ИсточникДанных.Имя = "ИсточникДанных1";
	ИсточникДанных.ТипИсточникаДанных = "local";
	
	НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
	НаборДанных.ИсточникДанных = "ИсточникДанных1";
	НаборДанных.Имя = "НаборДанных1";
	НаборДанных.ИмяОбъекта = "Данные";
	
	Для Каждого СтрокаТаблицы Из ТаблицаЗначений Цикл
		Поле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
		Поле.Поле = СтрокаТаблицы.Идентификатор;
		Поле.ПутьКДанным = СтрокаТаблицы.Идентификатор;
		Если ЗначениеЗаполнено(СтрокаТаблицы.Представление) Тогда
			Поле.Заголовок = СтрокаТаблицы.Представление;
		КонецЕсли;
		Поле.ТипЗначения = СтрокаТаблицы.ТипЗначения;
		
		Если ЗначениеЗаполнено(СтрокаТаблицы.Формат) Тогда
			ЗначениеПараметра = Поле.Оформление.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Формат"));
			Если ЗначениеПараметра <> Неопределено Тогда
				ЗначениеПараметра.Использование = Истина;
				ЗначениеПараметра.Значение = СтрокаТаблицы.Формат;
			КонецЕсли;
		КонецЕсли;
		
		ДополнительныеПараметры = Новый Структура("Порядок,ЭтоФункция,Скрытый,ВыражениеДляВставки");
		ЗаполнитьЗначенияСвойств(ДополнительныеПараметры, СтрокаТаблицы);
		
		ДополнительныеПараметры.Вставить("Картинка",  Base64Строка(СтрокаТаблицы.Картинка.ПолучитьДвоичныеДанные()));
		
		Поле.ПараметрыРедактирования.УстановитьЗначениеПараметра("Маска", 
			ОбщегоНазначения.ЗначениеВJSON(ДополнительныеПараметры));
	КонецЦикла;
	
	Возврат СхемаКомпоновкиДанных;
	
КонецФункции

Функция СхемаКомпоновкиДанныхИзДереваЗначений(ДеревоЗначений) Экспорт
	
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
	ИсточникДанных.Имя = "ИсточникДанных1";
	ИсточникДанных.ТипИсточникаДанных = "local";
	
	НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
	НаборДанных.ИсточникДанных = "ИсточникДанных1";
	НаборДанных.Имя = "НаборДанных1";
	НаборДанных.ИмяОбъекта = "Данные";
	
	ДобавитьГруппуЭлементовВНаборДанных(ДеревоЗначений, НаборДанных);
	
	Возврат СхемаКомпоновкиДанных;
	
КонецФункции

Функция ОписаниеПоля(ПутьКДанным, СпискиПолей) Экспорт
	
	СхемаКомпоновкиДанных = Неопределено;
	ИдентификаторСхемыКомпоновкиДанных = Неопределено;
	ПутьКДаннымВоВложеннойСхеме = Неопределено;
	ВладелецПоля = Неопределено;
	Тип = Неопределено;
	Папка = Неопределено;
	Таблица = Неопределено;
	
	Для Каждого НастройкиСписка Из СпискиПолей Цикл
		ИсточникиДоступныхПолей = НастройкиСписка.ИсточникиДоступныхПолей;
		КоллекцияПолей = НастройкиСписка.КоллекцияПолей;
		Если КоллекцияПолей = Неопределено Тогда
			НастройкиСписка.КоллекцияПолей = НоваяКоллекцияПолей();
			КоллекцияПолей = НастройкиСписка.КоллекцияПолей;
			ЗаполнитьСписокДоступныхРеквизитов(КоллекцияПолей, ИсточникиДоступныхПолей, , НастройкиСписка);
		КонецЕсли;

		Реквизит = НайтиПоле(ПутьКДанным, ПодчиненныеЭлементы(КоллекцияПолей), Ложь, ИсточникиДоступныхПолей, НастройкиСписка);
		Если Реквизит <> Неопределено Тогда
			Родитель = Родитель(Реквизит);
			Пока Родитель <> Неопределено Цикл
				Если Родитель.СвойНаборПолей Тогда
					Прервать;
				Иначе
					Родитель = Родитель(Родитель);
					Продолжить;
				КонецЕсли;
			КонецЦикла;
			
			Если Родитель <> Неопределено Тогда
				Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей(ИсточникиДоступныхПолей, НастройкиСписка, Родитель) Цикл
					Поле = ИсточникДоступныхПолей.КоллекцияПолей.НайтиПоле(Реквизит.Поле);
					Если Поле <> Неопределено Тогда
						ВладелецПоля = Родитель.ПутьКДанным;
						СхемаКомпоновкиДанных = ИсточникДоступныхПолей.СхемаКомпоновкиДанных;
						ИдентификаторСхемыКомпоновкиДанных = ИсточникДоступныхПолей.ИдентификаторСхемыКомпоновкиДанных;
						ПутьКДаннымВоВложеннойСхеме = Строка(Реквизит.Поле);
						Тип = Поле.ТипЗначения;
						Папка = Реквизит.Папка;
						Таблица = Реквизит.Таблица;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
			
			Если ВладелецПоля = Неопределено Тогда
				Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей(ИсточникиДоступныхПолей, НастройкиСписка) Цикл
					Поле = ИсточникДоступныхПолей.КоллекцияПолей.НайтиПоле(Реквизит.Поле);
					Если Поле <> Неопределено Тогда
						ВладелецПоля = "Ссылка";
						СхемаКомпоновкиДанных = ИсточникДоступныхПолей.СхемаКомпоновкиДанных;
						ИдентификаторСхемыКомпоновкиДанных = ИсточникДоступныхПолей.ИдентификаторСхемыКомпоновкиДанных;
						ПутьКДаннымВоВложеннойСхеме = Строка(Реквизит.Поле);
						Тип = Поле.ТипЗначения;
						Папка = Реквизит.Папка;
						Таблица = Реквизит.Таблица;
					КонецЕсли;
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("Поле", ПутьКДанным);
	Результат.Вставить("СхемаКомпоновкиДанных", СхемаКомпоновкиДанных);
	Результат.Вставить("ИдентификаторСхемыКомпоновкиДанных", ИдентификаторСхемыКомпоновкиДанных);
	Результат.Вставить("ПутьКДанным", ПутьКДаннымВоВложеннойСхеме);
	Результат.Вставить("Владелец", ВладелецПоля);
	Результат.Вставить("Формат", ФорматПоля(ПутьКДанным, СхемаКомпоновкиДанных));
	Результат.Вставить("Тип", Тип);
	Результат.Вставить("Папка", Папка);
	Результат.Вставить("Таблица", Таблица);
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  ТаблицаЗначений:
//   * КоллекцияПолей - ДеревоЗначений
//   * ИсточникиДоступныхПолей - ТаблицаЗначений
//   * СкобкиИдентификаторов - Булево
//   * СкобкиПредставлений - Булево
//   * ИспользоватьИдентификаторыДляФормул - Булево
//   * ПриОпределенииИсточниковДоступныхПолей - Строка
//
Функция ОписаниеСписковПолей() Экспорт
	
	Результат = Новый ТаблицаЗначений();
	Результат.Колонки.Добавить("КоллекцияПолей");
	Результат.Колонки.Добавить("ИсточникиДоступныхПолей");
	Результат.Колонки.Добавить("СкобкиИдентификаторов", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("СкобкиПредставлений", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ИспользоватьИдентификаторыДляФормул", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ПриОпределенииИсточниковДоступныхПолей", Новый ОписаниеТипов("Строка"));
	
	Возврат Результат;
	
КонецФункции

// Возвращаемое значение:
//  ТаблицаЗначений
// 
Функция КоллекцияИсточниковДоступныхПолей() Экспорт
	
	Результат = Новый ТаблицаЗначений;
	
	Для Каждого ОписаниеРеквизита Из РеквизитыСпискаИсточниковДоступныхПолей() Цикл
		ИмяРеквизита = ОписаниеРеквизита.Ключ;
		ТипРеквизита = ОписаниеРеквизита.Значение;
		Результат.Колонки.Добавить(ИмяРеквизита, ТипРеквизита);
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ИмяКолонкиПредставление(ИмяСпискаПолей) Экспорт
	
	Возврат ИмяСпискаПолей + "Представление";
	
КонецФункции

Функция ЭлементыФормулы(Знач Формула) Экспорт

	ВсеЭлементы = Новый Массив;
	ОперандыИФункции = Новый Соответствие;
	
	Разделители = "()/*-+%=<>, " + Символы.Таб + Символы.ПС;
	ОткрывающихСкобок = 0;
	ЭтоСтрокаВКавычках = Ложь;
	
	Операнд = "";
	
	Для Индекс = 1 По СтрДлина(Формула) Цикл

		Символ = Сред(Формула, Индекс, 1);
		ЭтоРазделитель = СтрНайти(Разделители, Символ) > 0;
		
		Если ОткрывающихСкобок = 0 И Символ = """" Тогда
			ЭтоСтрокаВКавычках = Не ЭтоСтрокаВКавычках;
			ВсеЭлементы.Добавить(Символ);
			Продолжить;
		КонецЕсли;
		
		Если ЭтоСтрокаВКавычках Тогда
			ВсеЭлементы.Добавить(Символ);
			Продолжить;
		КонецЕсли;

		Если Символ = "[" Тогда
			ОткрывающихСкобок = ОткрывающихСкобок + 1;
		КонецЕсли;
		
		Если Символ = "]" И ОткрывающихСкобок > 0 Тогда
			ОткрывающихСкобок = ОткрывающихСкобок - 1;
		КонецЕсли;
		
		Если ЭтоРазделитель И ОткрывающихСкобок = 0 Тогда
			Если ЗначениеЗаполнено(Операнд) Тогда
				ЭтоФункция = Ложь;
				Если Символ = "(" И СтрНайти(Операнд, ".") = 0 Тогда
					ЭтоФункция = Истина;
				КонецЕсли;
				
				Если ЭтоФункция Или Не ОбщегоНазначенияКлиентСервер.ЭтоЧисло(Операнд) Тогда
					ОперандыИФункции.Вставить(ВсеЭлементы.ВГраница() + 1, ЭтоФункция);
				КонецЕсли;
				
				ВсеЭлементы.Добавить(Операнд);
				Операнд = "";
			КонецЕсли;
			ВсеЭлементы.Добавить(Символ);
		Иначе
			Операнд = Операнд + Символ;
		КонецЕсли;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(Операнд) И Не ОбщегоНазначенияКлиентСервер.ЭтоЧисло(Операнд) Тогда
		ОперандыИФункции.Вставить(ВсеЭлементы.ВГраница() + 1, Ложь);
	КонецЕсли;
	
	ВсеЭлементы.Добавить(Операнд);
	
	Результат = Новый Структура;
	Результат.Вставить("ВсеЭлементы", ВсеЭлементы);
	Результат.Вставить("ОперандыИФункции", ОперандыИФункции);
	
	Возврат Результат;
	
КонецФункции

Функция КоллекцияПолей(Знач ИсточникПолей, Форма = Неопределено, Знач ИмяКоллекцииСКД = Неопределено) Экспорт

	КомпоновщикНастроек = КомпоновщикНастроекИсточникаПолей(ИсточникПолей, Форма);
	Если КомпоновщикНастроек = Неопределено Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Возврат КоллекцияПолейКомпоновщикаНастроек(КомпоновщикНастроек, ИмяКоллекцииСКД);
	
КонецФункции


Функция ПроверитьФормулу(Форма, ПредставлениеФормулы) Экспорт
	
	ЭлементыФормулы = ЭлементыФормулы(ПредставлениеФормулы);
	
	РаспознанныеЭлементы = Новый Соответствие;
	
	Для Каждого Элемент Из Форма.ПодключенныеСпискиПолей Цикл
		ИмяСпискаПолей = Элемент.ИмяСпискаПолей;
		КоллекцияПолей = Форма[ИмяСпискаПолей];
		СкобкиИдентификаторов = Элемент.СкобкиИдентификаторов;
		
		Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
			ПредставлениеОперанда = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
			ЭтоФункция = ОписаниеЭлемента.Значение;
			ПутьКДанным = ОчиститьКвадратныеСкобки(ПредставлениеОперанда);
			Реквизит = НайтиРеквизит(Форма, ИмяСпискаПолей, ПутьКДанным, КоллекцияПолей.ПолучитьЭлементы(), Истина);
			Если Реквизит <> Неопределено  Тогда
				Если ЭтоФункция <> Реквизит.ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				Операнд = Реквизит.ПутьКДанным;
				Если СкобкиИдентификаторов Тогда
					Операнд = ОбернутьВКвадратныеСкобки(Операнд);
				КонецЕсли;
				РаспознанныеЭлементы.Вставить(ОписаниеЭлемента.Ключ, Операнд);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Ошибки = Новый Массив;
	
	Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
		Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
		ЭтоФункция = ОписаниеЭлемента.Значение;
		
		Если РаспознанныеЭлементы[ОписаниеЭлемента.Ключ] = Неопределено Тогда
			Если ЭтоФункция Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Неизвестная функция в выражении - ""%1""'"),
					Операнд);
			Иначе
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Поле %1 не найдено в списке доступных полей'"),
					Операнд);
			КонецЕсли;
			Ошибки.Добавить(ТекстОшибки);
		КонецЕсли;
	КонецЦикла;
	
	Результат = СтрСоединить(Ошибки, Символы.ПС);
	Возврат Результат;
	
КонецФункции

Процедура ОбработчикКонструктораФормул(Форма, Параметр, ДополнительныеПараметры) Экспорт
	КлючОперации = ДополнительныеПараметры.КлючОперации;
	Если КлючОперации = "ОчиститьСтрокуПоиска" Тогда
		ОчиститьСтрокуПоиска(Форма, Параметр);
	ИначеЕсли КлючОперации = "ЗапуститьФоновыйПоискВСпискеПолей" Тогда
		Параметр = ЗапуститьФоновыйПоискВСпискеПолей(Форма);
	КонецЕсли;
КонецПроцедуры

// Запустить поиск в списке полей.
// 
// Параметры:
//  СтруктураФормы - Структура:
//    * 
// 
// Возвращаемое значение:
//  Неопределено, Структура - запустить поиск в списке полей:
//   * ДеревоЭлементов 
//   * НайденныеЭлементы - Массив
//
Функция ЗапуститьПоискВСпискеПолей(СтруктураФормы) Экспорт
	
	ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание();
	ЭтоФоновоеЗадание = (ТекущийСеанс <> Неопределено);
	
	ИмяСпискаПолей = СтруктураФормы.ИмяСписка;
	ИмяРеквизитаСтрокиПоиска = ИмяРеквизитаСтрокиПоискаСпискаПолей(ИмяСпискаПолей);
	Отбор = СтруктураФормы[ИмяРеквизитаСтрокиПоиска];
	ОтборУстановлен = ЗначениеЗаполнено(Отбор);
	
	Результат = Новый Структура;
	Результат.Вставить("ИмяСписка", ИмяСпискаПолей);
	
	Если ЭтоФоновоеЗадание Тогда
		ОбщегоНазначения.СообщитьПользователю(ОбщегоНазначения.ЗначениеВСтрокуXML(Результат));
	КонецЕсли;
	
	Если ОтборУстановлен Тогда
		УстановитьОтбор(СтруктураФормы, ИмяСпискаПолей, Отбор, СтруктураФормы[ИмяСпискаПолей]);
	КонецЕсли;
		
	Если ЭтоФоновоеЗадание Тогда
		Возврат Неопределено;
	Иначе
		ДеревоПоиска = СтруктураФормы[ИмяСпискаПолей];// см. ДеревоДоступныхРеквизитов
		СтруктураОтбора = Новый Структура("СоответствуетОтбору", Истина);
		МассивНайденныхЭлементов = ДеревоПоиска.Строки.НайтиСтроки(СтруктураОтбора, Истина);
		Если МассивНайденныхЭлементов.Количество()  <> 0 Тогда
			НайденныеСтроки = Новый Массив;
			Для Каждого НайденныйЭлемент Из МассивНайденныхЭлементов Цикл
				СтруктураСтроки = СтрокуДереваВСтруктуру(НайденныйЭлемент, ДеревоПоиска);
				НайденныеСтроки.Добавить(СтруктураСтроки);
			КонецЦикла;
			
			Результат = Новый Структура("НайденныеЭлементы", НайденныеСтроки);
			Возврат Результат;
		КонецЕсли;
		Возврат Неопределено;
	КонецЕсли;
КонецФункции

#КонецОбласти


#Область СлужебныеПроцедурыИФункции

Процедура УстановитьИдентификаторыСтрокДерева(Коллекция)
	Для Каждого Строка Из Коллекция.Строки Цикл
		Если Не ЗначениеЗаполнено(Строка.Идентификатор) Тогда
			Строка.Идентификатор = Новый УникальныйИдентификатор();
		КонецЕсли;
		УстановитьИдентификаторыСтрокДерева(Строка);
	КонецЦикла;
КонецПроцедуры

Функция ЗапуститьФоновыйПоискВСпискеПолей(Форма)
	
	ИмяТекущегоРеквизитаСтрокиПоиска = Форма.ИмяТекущейСтрокиПоиска;
	
	Если ЭтоАдресВременногоХранилища(Форма.АдресОписанияДлительнойОперации) Тогда
		СоответствиеДлительныхОпераций = ПолучитьИзВременногоХранилища(Форма.АдресОписанияДлительнойОперации);
	Иначе
		СоответствиеДлительныхОпераций = Новый Соответствие();
	КонецЕсли;
	
	Если СоответствиеДлительныхОпераций[ИмяТекущегоРеквизитаСтрокиПоиска] <> Неопределено Тогда
		ИдентификаторЗадания = СоответствиеДлительныхОпераций[ИмяТекущегоРеквизитаСтрокиПоиска];
		ДлительныеОперации.ОтменитьВыполнениеЗадания(ИдентификаторЗадания);
	КонецЕсли;
	
	СтрокаОтбора = Форма[ИмяТекущегоРеквизитаСтрокиПоиска];
	ИмяСписка = ИмяРеквизитаСпискаПолей(ИмяТекущегоРеквизитаСтрокиПоиска);
	
	ПодключенныеСпискиПолей = Форма.ПодключенныеСпискиПолей.Выгрузить();
	Отбор = Новый Структура("ИмяСпискаПолей", ИмяРеквизитаСпискаПолей(ИмяТекущегоРеквизитаСтрокиПоиска));
	ПодключенныеСпискиПолейСтрокиПоиска = ПодключенныеСпискиПолей.Скопировать(Отбор);
	
	ОтборУстановлен = ЗначениеЗаполнено(СтрокаОтбора);
		
	Если Не ОтборУстановлен Тогда
		ВыполнитьПоискВСпискеПолей(Форма);
		Возврат Неопределено;
	КонецЕсли;
	
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(Форма.УникальныйИдентификатор);
	
	СтруктураФормы = Новый Структура;

	СтруктураФормы.Вставить("ИмяСписка", ИмяСписка);		
	СтруктураФормы.Вставить("ПодключенныеСпискиПолей", ПодключенныеСпискиПолейСтрокиПоиска);
		
	Для Каждого ПодключенногоСпискаПолей Из ПодключенныеСпискиПолейСтрокиПоиска Цикл
		ИмяСпискаПолей = ПодключенногоСпискаПолей.ИмяСпискаПолей;
		ИмяРеквизитаСтрокиПоиска = ИмяРеквизитаСтрокиПоискаСпискаПолей(ИмяСпискаПолей);
					
		СтруктураФормы.Вставить(ИмяРеквизитаСтрокиПоиска, Форма[ИмяРеквизитаСтрокиПоиска]);
		ДеревоПолей = ДеревоДоступныхРеквизитов(Форма, ПодключенногоСпискаПолей.ИмяСпискаПолей);
		
		ЗначениеВДанныеФормы(ДеревоПолей, Форма[ПодключенногоСпискаПолей.ИмяСпискаПолей]);
		УстановитьИдентификаторыСтрокДерева(ДеревоПолей);
		СтруктураФормы.Вставить(ПодключенногоСпискаПолей.ИмяСпискаПолей, ДеревоПолей);
		
		ТаблицаИсточников = ДанныеФормыВЗначение(Форма[ПодключенногоСпискаПолей.ИмяСпискаИсточников], Тип("ТаблицаЗначений"));
		Для Каждого СтрокаТаблицы Из ТаблицаИсточников Цикл
			Если СтрокаТаблицы.СхемаКомпоновкиДанных <> Неопределено Тогда
				Если ЭтоАдресВременногоХранилища(СтрокаТаблицы.СхемаКомпоновкиДанных) Тогда
					СхемаКомпоновкиДанных = ПолучитьИзВременногоХранилища(СтрокаТаблицы.СхемаКомпоновкиДанных);
				Иначе
					СхемаКомпоновкиДанных = СтрокаТаблицы.СхемаКомпоновкиДанных;
				КонецЕсли;
				СтрокаТаблицы.СхемаКомпоновкиДанных = ОбщегоНазначения.ЗначениеВСтрокуXML(СхемаКомпоновкиДанных);
			КонецЕсли;
			Контейнер = ДоступныеПоляВКонтейнерСКД(СтрокаТаблицы.КоллекцияПолей);
			СтрокаТаблицы.КоллекцияПолей = ОбщегоНазначения.ЗначениеВСтрокуXML(Контейнер);
		КонецЦикла;
		СтрокаТаблицыИсточников = ОбщегоНазначения.ЗначениеВСтрокуXML(ТаблицаИсточников);
		СтруктураФормы.Вставить(ПодключенногоСпискаПолей.ИмяСпискаИсточников, СтрокаТаблицыИсточников);
	КонецЦикла;
	
	СтруктураРеквизитов = Новый Структура("КомпоновщикНастроек, НастройкиОтчета, ВладелецМакета");
	ЗаполнитьЗначенияСвойств(СтруктураРеквизитов, Форма);
	
	ДлительнаяОперация = ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, "КонструкторФормулСлужебный.ЗапуститьПоискВСпискеПолей", СтруктураФормы);

	СоответствиеДлительныхОпераций.Вставить(ИмяТекущегоРеквизитаСтрокиПоиска, ДлительнаяОперация.ИдентификаторЗадания);
	Если ЭтоАдресВременногоХранилища(Форма.АдресОписанияДлительнойОперации) Тогда
		ПоместитьВоВременноеХранилище(СоответствиеДлительныхОпераций, Форма.АдресОписанияДлительнойОперации);
	Иначе
		Форма.АдресОписанияДлительнойОперации = ПоместитьВоВременноеХранилище(СоответствиеДлительныхОпераций, Форма.УникальныйИдентификатор);
	КонецЕсли;
		
	Возврат	ДлительнаяОперация;
	
КонецФункции

// Возвращаемое значение: 
//  ДеревоЗначений:
//   * Имя - Строка
//   * Заголовок - Строка
//   * Поле - ПолеКомпоновкиДанных
//   * ПутьКДанным - Строка
//   * ПредставлениеПутиКДанным - Строка
//   * Тип - ОписаниеТипов
//   * Картинка - Картинка
//   * Папка - Булево
//   * Таблица - Булево
//   * СвойНаборПолей - Булево
//   * Отступ - Строка
//   * СоответствуетОтбору - Булево
//   * ПодчиненныйЭлементСоответствуетОтбору - Булево
//   * ЭтоГруппа - Булево
//   * ЭтоФункция - Булево
//   * Идентификатор - УникальныйИдентификатор
//						
Функция ДеревоДоступныхРеквизитов(Знач Форма, Знач ИмяСписка)
	ДеревоТекущегоСписка = ДанныеФормыВЗначение(Форма[ИмяСписка], Тип("ДеревоЗначений"));// ДеревоЗначений
	Если ДеревоТекущегоСписка.Колонки.Найти("Идентификатор") = Неопределено Тогда
		ДеревоТекущегоСписка.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("УникальныйИдентификатор"));
	КонецЕсли;
	Возврат ДеревоТекущегоСписка;
КонецФункции

Функция ДоступныеПоляИзКонтейнераСКД(Контейнер)
	Возврат КоллекцияПолей(Контейнер);
КонецФункции

// Параметры:
//  Форма - ФормаКлиентскогоПриложения
//  Параметры - см. ПараметрыДобавленияСпискаПолей
//
Процедура ДобавитьСписокПолейНаФорму(Форма, Параметры) Экспорт
	
	ПараметрыДобавления = ПараметрыДобавленияСпискаПолей();
	ЗаполнитьЗначенияСвойств(ПараметрыДобавления, Параметры);
	
	ДобавляемыеРеквизиты = Новый Массив;
	
	ЗначенияРеквизитов = Новый Структура("ПодключенныеСпискиПолей, АдресОписанияДлительнойОперации");
	ЗаполнитьЗначенияСвойств(ЗначенияРеквизитов, Форма);
	ПодключенныеСпискиПолей = ЗначенияРеквизитов.ПодключенныеСпискиПолей;
	Если ПодключенныеСпискиПолей = Неопределено Тогда
		ИмяРеквизитаПодключенныеСпискиПолей = "ПодключенныеСпискиПолей";
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяРеквизитаПодключенныеСпискиПолей, Новый ОписаниеТипов("ТаблицаЗначений")));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ИмяСпискаПолей", Новый ОписаниеТипов("Строка"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ИмяСпискаИсточников", Новый ОписаниеТипов("Строка"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("СкобкиИдентификаторов", Новый ОписаниеТипов("Булево"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("СкобкиПредставлений", Новый ОписаниеТипов("Булево"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ИспользоватьИдентификаторыДляФормул", Новый ОписаниеТипов("Булево"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ПриОпределенииИсточниковДоступныхПолей", Новый ОписаниеТипов("Строка"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("РазворачиваемыеВетки", Новый ОписаниеТипов("Строка"), ИмяРеквизитаПодключенныеСпискиПолей));
		
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ИмяТекущейСтрокиПоиска", Новый ОписаниеТипов("Строка")));
	КонецЕсли;
	
	АдресОписанияДлительнойОперации = ЗначенияРеквизитов.АдресОписанияДлительнойОперации;
	Если АдресОписанияДлительнойОперации = Неопределено Тогда
		ИмяРеквизитаПодключенныеСпискиПолей = "ПодключенныеСпискиПолей";
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("ИспользоватьФоновыйПоиск", Новый ОписаниеТипов("Булево"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("КоличествоСимволовДляНачалаПоиска", Новый ОписаниеТипов("Число"), ИмяРеквизитаПодключенныеСпискиПолей));
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы("АдресОписанияДлительнойОперации", Новый ОписаниеТипов("Строка")));
	КонецЕсли;
	
	ИмяСпискаПолей = ПараметрыДобавления.ИмяСписка;
	Если НайтиРеквизитФормы(Форма, ИмяСпискаПолей) = Неопределено Тогда
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяСпискаПолей, Новый ОписаниеТипов("ДеревоЗначений")));
	КонецЕсли;
	
	Для Каждого ОписаниеРеквизита Из РеквизитыПодключаемогоСписка() Цикл
		ИмяРеквизита = ОписаниеРеквизита.Ключ;
		Если НайтиРеквизитФормы(Форма, ИмяРеквизита) = Неопределено Тогда
			ТипРеквизита = ОписаниеРеквизита.Значение;
			ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяРеквизита, ТипРеквизита, ИмяСпискаПолей));
		КонецЕсли;
	КонецЦикла;
	
	ИмяСтрокиПоиска = ИмяРеквизитаСтрокиПоискаСпискаПолей(ИмяСпискаПолей);
	ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяСтрокиПоиска, Новый ОписаниеТипов("Строка")));
	
	ИмяСпискаИсточников = ИмяСпискаПолей + "Источники";
	ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяСпискаИсточников, Новый ОписаниеТипов("ТаблицаЗначений")));
	Для Каждого ОписаниеРеквизита Из РеквизитыСпискаИсточниковДоступныхПолей() Цикл
		ИмяРеквизита = ОписаниеРеквизита.Ключ;
		ТипРеквизита = ОписаниеРеквизита.Значение;
		ДобавляемыеРеквизиты.Добавить(Новый РеквизитФормы(ИмяРеквизита, ТипРеквизита, ИмяСпискаИсточников));
	КонецЦикла;
	
	Форма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
	
	МестоРазмещенияСтрокиПоиска = ПараметрыДобавления.МестоРазмещенияСтрокиПоиска;
	Если Не ЗначениеЗаполнено(МестоРазмещенияСтрокиПоиска) Тогда
		МестоРазмещенияСтрокиПоиска = ПараметрыДобавления.МестоРазмещенияСписка;
	КонецЕсли;
	
	СписокПолей = Форма.Элементы.Найти(ИмяСпискаПолей);
	
	ГруппаПоиска = Форма.Элементы.Добавить("Группа" + ИмяСтрокиПоиска, Тип("ГруппаФормы"), МестоРазмещенияСтрокиПоиска);
	ГруппаПоиска.Вид = ВидГруппыФормы.ОбычнаяГруппа;
	ГруппаПоиска.Отображение = ОтображениеОбычнойГруппы.Нет;
	ГруппаПоиска.ОтображатьЗаголовок = Ложь; 
	ГруппаПоиска.Группировка = ГруппировкаПодчиненныхЭлементовФормы.ГоризонтальнаяВсегда;
	
	СтрокаПоиска = Форма.Элементы.Добавить(ИмяСтрокиПоиска, Тип("ПолеФормы"), ГруппаПоиска);
	
	ИмяКомандыОчистки = ИмяСтрокиПоиска + "Очистка";
	Если Форма.Команды.Найти(ИмяКомандыОчистки) = Неопределено Тогда
		Команда = Форма.Команды.Добавить(ИмяСтрокиПоиска + "Очистка");
		Команда.Действие = "Подключаемый_СтрокаПоискаОчистка";
		Команда.Отображение = ОтображениеКнопки.Картинка;
	КонецЕсли;
	
	КнопкаОчисткиПоиска = Форма.Элементы.Добавить(ИмяКомандыОчистки, Тип("КнопкаФормы"), ГруппаПоиска);
	КнопкаОчисткиПоиска.Вид = ВидКнопкиФормы.ОбычнаяКнопка;
	КнопкаОчисткиПоиска.Картинка = БиблиотекаКартинок.ПолеВводаОчистить;
	КнопкаОчисткиПоиска.ВертикальноеПоложениеВГруппе = ВертикальноеПоложениеЭлемента.Центр;
	КнопкаОчисткиПоиска.ИмяКоманды = ИмяКомандыОчистки;
	КнопкаОчисткиПоиска.ОтображениеФигуры = ОтображениеФигурыКнопки.ПриАктивности;
	КнопкаОчисткиПоиска.Заголовок = НСтр("ru = 'Очистить'");
	
	Если СписокПолей <> Неопределено Тогда
		Форма.Элементы.Переместить(ГруппаПоиска, МестоРазмещенияСтрокиПоиска, СписокПолей);
	КонецЕсли;
				
	СтрокаПоиска.ПутьКДанным = ИмяСтрокиПоиска;
	СтрокаПоиска.Вид = ВидПоляФормы.ПолеВвода;
	СтрокаПоиска.ПодсказкаВвода = ПараметрыДобавления.ПодсказкаВводаСтрокиПоиска;
	СтрокаПоиска.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
	СтрокаПоиска.УстановитьДействие("ИзменениеТекстаРедактирования", "Подключаемый_СтрокаПоискаИзменениеТекстаРедактирования");
	СтрокаПоиска.АвтоМаксимальнаяШирина = Ложь;
	СтрокаПоиска.ОбновлениеТекстаРедактирования = ОбновлениеТекстаРедактирования.НеИспользовать;
	СтрокаПоиска.Заголовок = НСтр("ru = 'Найти'");
	
	Если СписокПолей = Неопределено Тогда
		СписокПолей = Форма.Элементы.Добавить(ИмяСпискаПолей, Тип("ТаблицаФормы"), ПараметрыДобавления.МестоРазмещенияСписка);
		СписокПолей.ПутьКДанным = ИмяСпискаПолей;
	КонецЕсли;
	
	СписокПолей.НачальноеОтображениеДерева = НачальноеОтображениеДерева.НеРаскрывать;
	СписокПолей.ПоложениеЗаголовка = ПоложениеЗаголовкаЭлементаФормы.Нет;
	СписокПолей.Шапка = Ложь;
	СписокПолей.ГоризонтальныеЛинии = Ложь;
	СписокПолей.ВертикальныеЛинии = Ложь;
	СписокПолей.ИзменятьСоставСтрок = Ложь;
	СписокПолей.ИзменятьПорядокСтрок = Ложь;
	СписокПолей.РежимВыделения = РежимВыделенияТаблицы.Одиночный;
	СписокПолей.КоманднаяПанель.Видимость = Ложь;
	СписокПолей.УстановитьДействие("ПередРазворачиванием", "Подключаемый_СписокПолейПередРазворачиванием");
	СписокПолей.УстановитьДействие("НачалоПеретаскивания", "Подключаемый_СписокПолейНачалоПеретаскивания");
	
	Для Каждого КнопкаКонтекстногоМеню Из ПараметрыДобавления.КонтекстноеМеню Цикл
		Кнопка = Форма.Элементы.Добавить(ИмяСпискаПолей + КнопкаКонтекстногоМеню.Ключ, Тип("КнопкаФормы"), СписокПолей.КонтекстноеМеню);
		Кнопка.ИмяКоманды = КнопкаКонтекстногоМеню.Значение;
		Кнопка.Вид = ВидКнопкиФормы.КнопкаКоманднойПанели; 
	КонецЦикла;
	
	Для Каждого Обработчик Из ПараметрыДобавления.ОбработчикиСписка Цикл
		ИмяСобытия = Обработчик.Ключ;
		ИмяПроцедуры = Обработчик.Значение;
		СписокПолей.УстановитьДействие(ИмяСобытия, ИмяПроцедуры);
	КонецЦикла;
	
	ГруппаКолонок = Форма.Элементы.Добавить(ИмяСпискаПолей + "КартинкаИПредставление", Тип("ГруппаФормы"), СписокПолей);
	ГруппаКолонок.Группировка = ГруппировкаКолонок.ВЯчейке;
	
	КартинкаПоля = Форма.Элементы.Добавить(ИмяСпискаПолей + "Картинка", Тип("ПолеФормы"), ГруппаКолонок);
	КартинкаПоля.ПутьКДанным = ИмяСпискаПолей + ".Картинка";
	КартинкаПоля.Вид = ВидПоляФормы.ПолеКартинки;
	КартинкаПоля.ОтображатьВШапке = Ложь;
	КартинкаПоля.Заголовок = НСтр("ru = 'Картинка'");
	
	ПредставлениеПоля = Форма.Элементы.Добавить(ИмяКолонкиПредставление(ИмяСпискаПолей), Тип("ПолеФормы"), ГруппаКолонок);
	ПредставлениеПоля.ПутьКДанным = ИмяСпискаПолей + ".Заголовок";
	ПредставлениеПоля.Вид = ВидПоляФормы.ПолеВвода;
	ПредставлениеПоля.ТолькоПросмотр = Истина;
	ПредставлениеПоля.Заголовок = НСтр("ru = 'Заголовок'");
	
	ПредставлениеПоля = Форма.Элементы.Добавить(ИмяСпискаПолей + "ПредставлениеПутиКДанным", Тип("ПолеФормы"), ГруппаКолонок);
	ПредставлениеПоля.ПутьКДанным = ИмяСпискаПолей + ".ПредставлениеПутиКДанным";
	ПредставлениеПоля.Вид = ВидПоляФормы.ПолеНадписи;
	ПредставлениеПоля.ТолькоПросмотр = Истина;
	ПредставлениеПоля.Видимость = Ложь;
	ПредставлениеПоля.Заголовок = НСтр("ru = 'Поле'");
	
	ПодключенныеСпискиПолей = Форма.ПодключенныеСпискиПолей; // ТаблицаЗначений
	ПодключенныйСписок = ПодключенныеСпискиПолей.Добавить();
	ПодключенныйСписок.ИмяСпискаПолей = ИмяСпискаПолей;
	ПодключенныйСписок.ИмяСпискаИсточников = ИмяСпискаИсточников;
	ПодключенныйСписок.СкобкиИдентификаторов = ПараметрыДобавления.СкобкиИдентификаторов;
	ПодключенныйСписок.СкобкиПредставлений = ПараметрыДобавления.СкобкиПредставлений;
	ПодключенныйСписок.ИспользоватьИдентификаторыДляФормул = ПараметрыДобавления.ИспользоватьИдентификаторыДляФормул;
	ПодключенныйСписок.ПриОпределенииИсточниковДоступныхПолей = ПараметрыДобавления.ПриОпределенииИсточниковДоступныхПолей;
	Если ПараметрыДобавления.ИспользоватьФоновыйПоиск Тогда 
		ПодключенныйСписок.ИспользоватьФоновыйПоиск = ПараметрыДобавления.ИспользоватьФоновыйПоиск;
		ПодключенныйСписок.КоличествоСимволовДляНачалаПоиска = ПараметрыДобавления.КоличествоСимволовДляНачалаПоиска;
	КонецЕсли;
	
	ИсточникиДоступныхПолей = Форма[ИмяСпискаИсточников]; // ТаблицаЗначений
	
	КоллекцииПолей = ПараметрыДобавления.КоллекцииПолей;
	Если ТипЗнч(КоллекцииПолей) = Тип("Массив") Тогда
		КоллекцииПолей = Новый СписокЗначений;
		КоллекцииПолей.ЗагрузитьЗначения(ПараметрыДобавления.КоллекцииПолей);
	КонецЕсли;
	
	Для Каждого Элемент Из КоллекцииПолей Цикл
		КоллекцияПолей = Элемент.Значение;
		ИсточникДанных = Элемент.Представление;
		Если Не ЗначениеЗаполнено(ИсточникДанных) Тогда
			ИсточникДанных = ПараметрыДобавления.ИмяОсновногоИсточника;
		КонецЕсли;
		ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить();
		Если ТипЗнч(КоллекцияПолей) = Тип("Строка") И ЭтоАдресВременногоХранилища(КоллекцияПолей) Тогда
			ИсточникДоступныхПолей.СхемаКомпоновкиДанных = КоллекцияПолей;
			ИсточникДоступныхПолей.КоллекцияПолей = КоллекцияПолей(КоллекцияПолей);
		Иначе
			ИсточникДоступныхПолей.КоллекцияПолей = КоллекцияПолей;
		КонецЕсли;
		ИсточникДоступныхПолей.ИсточникДанных = ИсточникДанных;
		ИсточникДоступныхПолей.Замещать = ПараметрыДобавления.Замещать;
	КонецЦикла;
	
	Для Каждого ИсточникДоступныхПолей Из ПараметрыДобавления.ИсточникиДоступныхПолей Цикл
		ЗаполнитьЗначенияСвойств(ИсточникиДоступныхПолей.Добавить(), ИсточникДоступныхПолей);
	КонецЦикла;
	
	ДеревоПолей = Форма.РеквизитФормыВЗначение(ИмяСпискаПолей);
	ТаблицаИсточников = Форма.РеквизитФормыВЗначение(ИмяСпискаИсточников);
	
	ЗаполнитьСписокДоступныхРеквизитов(ДеревоПолей, ТаблицаИсточников, , ПодключенныйСписок, Форма.УникальныйИдентификатор);
	
	Форма.ЗначениеВРеквизитФормы(ДеревоПолей, ИмяСпискаПолей);
	Форма.ЗначениеВРеквизитФормы(ТаблицаИсточников, ИмяСпискаИсточников);
	
	УстановитьУсловноеОформление(Форма, ИмяСпискаПолей);
	
КонецПроцедуры

Функция НайтиРеквизитФормы(Форма, ИмяРеквизита)
	МассивРеквизитов = Форма.ПолучитьРеквизиты();
	Для Каждого РеквизитФормы Из МассивРеквизитов Цикл
		Если РеквизитФормы.Имя = ИмяРеквизита Тогда
			Возврат РеквизитФормы;
		КонецЕсли;
	КонецЦикла;
	Возврат Неопределено;
КонецФункции

// Возвращаемое значение:
//  Структура:
//   * МестоРазмещенияСписка - ГруппаФормы
//                           - ТаблицаФормы
//                           - ФормаКлиентскогоПриложения
//   * ИспользоватьФоновыйПоиск - Булево
//   * КоличествоСимволовДляНачалаПоиска - Число
//   * ИмяСписка - Строка
//   * КоллекцииПолей - Массив
//   * МестоРазмещенияСтрокиПоиска - ГруппаФормы
//                                 - ТаблицаФормы
//                                 - ФормаКлиентскогоПриложения
//   * ПодсказкаВводаСтрокиПоиска - Строка
//   * ОбработчикиСписка - Структура
//   * ВключатьГруппыВПутьКДанным - Булево
//   * СкобкиИдентификаторов - Булево
//   * СкобкиПредставлений - Булево
//   * ИсточникиДоступныхПолей - см. КоллекцияИсточниковДоступныхПолей
//   * ИспользоватьИдентификаторыДляФормул - Булево
//   * ПриОпределенииИсточниковДоступныхПолей - Строка
//   * ИмяОсновногоИсточника - Строка
//   * Замещать - Булево
//
Функция ПараметрыДобавленияСпискаПолей() Экспорт
	
	Результат = Новый Структура;
	Результат.Вставить("МестоРазмещенияСписка");
	Результат.Вставить("ИспользоватьФоновыйПоиск", Ложь);
	Результат.Вставить("КоличествоСимволовДляНачалаПоиска", 3);
	Результат.Вставить("ИмяСписка", "ДоступныеПоля");
	Результат.Вставить("КоллекцииПолей", Новый Массив);
	Результат.Вставить("МестоРазмещенияСтрокиПоиска");
	Результат.Вставить("ПодсказкаВводаСтрокиПоиска", НСтр("ru = 'Найти...'"));
	Результат.Вставить("ОбработчикиСписка", Новый Структура);
	Результат.Вставить("ВключатьГруппыВПутьКДанным", Истина);
	Результат.Вставить("СкобкиИдентификаторов", Ложь);
	Результат.Вставить("СкобкиПредставлений", Истина);
	Результат.Вставить("ИсточникиДоступныхПолей", КоллекцияИсточниковДоступныхПолей());
	Результат.Вставить("ИспользоватьИдентификаторыДляФормул", Ложь);
	Результат.Вставить("ПриОпределенииИсточниковДоступныхПолей", "");
	Результат.Вставить("ИмяОсновногоИсточника", "");
	Результат.Вставить("КонтекстноеМеню", Новый Структура);
	Результат.Вставить("Замещать", Ложь);
	
	Возврат Результат;
	
КонецФункции

Процедура ЗаполнитьДеревоПоДоступнымПолям(СтрокаДерева, ДоступныеПоля)
	Для Каждого ДоступноеПоле Из ДоступныеПоля.Элементы Цикл
		НоваяСтрока = СтрокаДерева.Строки.Добавить();
		ЗаполнитьЗначенияСвойств(НоваяСтрока, ДоступноеПоле);
		НоваяСтрока.Идентификатор = Строка(ДоступноеПоле.Поле);
		Родитель = ДоступноеПоле.Родитель;
		
		Если Родитель <> Неопределено И СтрНачинаетсяС(НоваяСтрока.Идентификатор, Строка(Родитель.Поле)) Тогда
			НоваяСтрока.Идентификатор = Сред(НоваяСтрока.Идентификатор, СтрДлина(Строка(Родитель.Поле)) + 2);
		КонецЕсли;
			
		НоваяСтрока.Представление = ДоступноеПоле.Заголовок;
		НоваяСтрока.Папка = ДоступноеПоле.Папка И Не ДоступноеПоле.Таблица;
		Если (ДоступноеПоле.Папка Или ДоступноеПоле.Таблица) И ДоступноеПоле.Элементы.Количество() <> 0 Тогда
			ЗаполнитьДеревоПоДоступнымПолям(НоваяСтрока, ДоступноеПоле);
		КонецЕсли;
	КонецЦикла;
КонецПроцедуры

Процедура ОчиститьСтрокуПоиска(Форма, ИмяЭлемента)
	
	Элемент = Форма.Элементы[СтрЗаменить(ИмяЭлемента, "Очистка", "")];
	Форма.ТекущийЭлемент = Элемент;
	Форма[Элемент.Имя] = "";
	
КонецПроцедуры

Процедура ОбновитьКоллекцииПолей(Форма, КоллекцииПолей, ИмяСпискаПолей = "ДоступныеПоля") Экспорт
	
	ИсточникиДоступныхПолей = СписокИсточниковДоступныхПолей(Форма, ИмяСпискаПолей); // ДанныеФормыКоллекция
	ИмяОсновногоИсточникаДанных = ИмяОсновногоИсточникаДанных(ИсточникиДоступныхПолей);
	ИсточникиДоступныхПолей.Очистить();
	
	КоллекцииПолейИсточниковДанных = КоллекцииПолей;
	Если ТипЗнч(КоллекцииПолей) = Тип("Массив") Тогда
		КоллекцииПолейИсточниковДанных = Новый СписокЗначений;
		КоллекцииПолейИсточниковДанных.ЗагрузитьЗначения(КоллекцииПолей);
	КонецЕсли;
	
	Для Индекс = 0 По КоллекцииПолей.Количество()-1 Цикл
		КоллекцияПолей = КоллекцииПолейИсточниковДанных[Индекс].Значение;
		ИсточникДанных = КоллекцииПолейИсточниковДанных[Индекс].Представление;
		Если Не ЗначениеЗаполнено(ИсточникДанных) Тогда
			ИсточникДанных = ИмяОсновногоИсточникаДанных;
		КонецЕсли;
		
		ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Вставить(Индекс);
		ИсточникДоступныхПолей.ИсточникДанных = ИсточникДанных;
		ИсточникДоступныхПолей.КоллекцияПолей = КоллекцияПолей;
	КонецЦикла;
	
	Форма[ИмяСпискаПолей].ПолучитьЭлементы().Очистить();
	НастройкиСписка = КонструкторФормулКлиентСервер.НастройкиСпискаПолей(Форма, ИмяСпискаПолей);
	ЗаполнитьСписокДоступныхРеквизитов(Форма[ИмяСпискаПолей], ИсточникиДоступныхПолей, , НастройкиСписка);
	
КонецПроцедуры

Функция ТаблицаПолей() Экспорт
	
	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("ТипЗначения", Новый ОписаниеТипов("ОписаниеТипов"));
	Результат.Колонки.Добавить("Картинка", Новый ОписаниеТипов("Картинка"));
	Результат.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
	Результат.Колонки.Добавить("Формат", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("ЭтоФункция", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("Скрытый", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ВыражениеДляВставки", Новый ОписаниеТипов("Строка"));
	
	Возврат Результат;
	
КонецФункции

Функция ДеревоПолей() Экспорт
	
	Результат = Новый ДеревоЗначений();
	Результат.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("ТипЗначения", Новый ОписаниеТипов("ОписаниеТипов"));
	Результат.Колонки.Добавить("Картинка", Новый ОписаниеТипов("Картинка"));
	Результат.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
	Результат.Колонки.Добавить("Папка", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("Таблица", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("Формат", Новый ОписаниеТипов("Строка"));
	Результат.Колонки.Добавить("ЭтоФункция", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("Скрытый", Новый ОписаниеТипов("Булево"));
	Результат.Колонки.Добавить("ВыражениеДляВставки", Новый ОписаниеТипов("Строка"));
	
	Возврат Результат;
	
КонецФункции

Функция КомпоновщикНастроекИсточникаПолей(Знач ИсточникПолей, Форма = Неопределено) Экспорт
	
	Если ЭтоАдресВременногоХранилища(ИсточникПолей) Тогда
		ИсточникПолей = ПолучитьИзВременногоХранилища(ИсточникПолей);
	КонецЕсли;
	
	СхемаКомпоновкиДанных = ИсточникПолей;
	Если ТипЗнч(ИсточникПолей) = Тип("ТаблицаЗначений") Тогда
		СхемаКомпоновкиДанных = СхемаКомпоновкиДанныхИзТаблицыЗначений(ИсточникПолей);
	ИначеЕсли ТипЗнч(ИсточникПолей) = Тип("ДеревоЗначений") Тогда
		СхемаКомпоновкиДанных = СхемаКомпоновкиДанныхИзДереваЗначений(ИсточникПолей);
	КонецЕсли;
	
	Если ТипЗнч(СхемаКомпоновкиДанных) <> Тип("СхемаКомпоновкиДанных") Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Если Форма <> Неопределено Тогда
		УникальныйИдентификатор = Форма.УникальныйИдентификатор;
	КонецЕсли;
	АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных, УникальныйИдентификатор);
	ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы);
	
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
	КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
	
	Возврат КомпоновщикНастроек;
	
КонецФункции

Функция КоллекцияПолейКомпоновщикаНастроек(Знач КомпоновщикНастроек, Знач ИмяКоллекцииСКД = Неопределено)
	
	Если Не ЗначениеЗаполнено(ИмяКоллекцииСКД) Тогда
		ИмяКоллекцииСКД = "ДоступныеПоляОтбора";
	КонецЕсли;
	
	ОписаниеИмениКоллекцииПолей = СтрРазделить(ИмяКоллекцииСКД, ".");
	КоллекцияПолей = КомпоновщикНастроек.Настройки;
	
	Для Каждого Элемент Из ОписаниеИмениКоллекцииПолей Цикл 
		КоллекцияПолей = КоллекцияПолей[Элемент];
	КонецЦикла;
	
	Возврат КоллекцияПолей;
КонецФункции

Процедура ЗаполнитьСписокДоступныхРеквизитов(Знач ТекущийРеквизит, ИсточникиДоступныхПолей, Знач Отбор = "", 
	НастройкиСписка = Неопределено, УникальныйИдентификаторФормы = Неопределено)
	
	КоллекцииДоступныхПолей = КоллекцииДоступныхПолей(ТекущийРеквизит, ИсточникиДоступныхПолей, НастройкиСписка, УникальныйИдентификаторФормы);
	ДоступныеРеквизиты = ДоступныеРеквизиты(КоллекцииДоступныхПолей);
	
	КоллекцияРеквизитов = ПодчиненныеЭлементы(ТекущийРеквизит);
	ПолеСсылкаДобавлено = Ложь;
	Для Каждого ДоступныйРеквизит Из ДоступныеРеквизиты Цикл
		Если ДоступныйРеквизит.Имя = "Ссылка" Тогда
			Если ТипЗнч(ТекущийРеквизит) <> Тип("ДанныеФормыДерево") И ТипЗнч(ТекущийРеквизит) <> Тип("ДеревоЗначений")
				Или ПолеСсылкаДобавлено Тогда
				Продолжить;
			КонецЕсли;
			ПолеСсылкаДобавлено = Истина;
		КонецЕсли;
		
		Реквизит = КоллекцияРеквизитов.Добавить();
		ЗаполнитьЗначенияСвойств(Реквизит, ДоступныйРеквизит);
		
		Если Родитель(Реквизит) <> Неопределено Тогда
			Родитель = Родитель(Реквизит);
			Если Реквизит.ЭтоГруппа Тогда
				Реквизит.ПутьКДанным = Родитель.ПутьКДанным;
				Реквизит.ПредставлениеПутиКДанным = Строка(Родитель.ПредставлениеПутиКДанным);
			Иначе
				Если ЗначениеЗаполнено(Родитель.ПутьКДанным) Тогда
					Реквизит.ПутьКДанным = Родитель.ПутьКДанным + "." + Реквизит.Имя;
					Реквизит.ПредставлениеПутиКДанным = Строка(Родитель.ПредставлениеПутиКДанным) + "." + Реквизит.Заголовок;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
		
		Если ДоступныйРеквизит.ЕстьПодчиненные Тогда
			ПодчиненныеЭлементы(Реквизит).Добавить();
		ИначеЕсли НастройкиСписка <> Неопределено И ЗначениеЗаполнено(НастройкиСписка.ПриОпределенииИсточниковДоступныхПолей) Тогда
			КоллекцииПолейРеквизита = КоллекцииДоступныхПолей(Реквизит, ИсточникиДоступныхПолей, НастройкиСписка, УникальныйИдентификаторФормы);
			Если ЗначениеЗаполнено(КоллекцииПолейРеквизита) И Не СтрНайти(Реквизит.ПутьКДанным, Реквизит.Имя + ".")
				И ЗначениеЗаполнено(КоллекцииПолейРеквизита[0].Элементы) Тогда
					ПодчиненныеЭлементы(Реквизит).Добавить();
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Функция ДоступныеРеквизиты(КоллекцииДоступныхПолей)

	ДоступныеРеквизиты = НоваяКоллекцияДоступныхРеквизитов();
	ДоступныеРеквизиты.Колонки.Добавить("ЕстьПодчиненные", Новый ОписаниеТипов("Булево"));
	ДоступныеРеквизиты.Колонки.Добавить("Порядок", Новый ОписаниеТипов("Число"));
	ДоступныеРеквизиты.Индексы.Добавить("Поле");
	
	СлужебныеПоля = СлужебныеПоля();
	ТипыПрисоединенныхФайлов = ТипыПрисоединенныхФайлов();
	ПрефиксыПолейКартинка = ПрефиксыПолейКартинка(); 
	
	Для Каждого КоллекцияДоступныхПолей Из КоллекцииДоступныхПолей Цикл
		Для Каждого ОписаниеПоля Из КоллекцияДоступныхПолей.Элементы Цикл
			Если ЭтоСлужебноеПоле(ОписаниеПоля, СлужебныеПоля) Тогда
				Продолжить;
			КонецЕсли;
			
			НайденныеРеквизиты = ДоступныеРеквизиты.НайтиСтроки(Новый Структура("Поле", ОписаниеПоля.Поле));
			Для Каждого Реквизит Из НайденныеРеквизиты Цикл
				Если Не ОписаниеПоля.Тип.СодержитТип(Тип("ТаблицаЗначений")) Тогда
					Реквизит.Тип = Новый ОписаниеТипов(Реквизит.Тип, ОписаниеПоля.Тип.Типы());
				КонецЕсли;
			КонецЦикла;
			Если НайденныеРеквизиты.Количество() > 0 Тогда
				Продолжить;
			КонецЕсли;

			Реквизит = ДоступныеРеквизиты.Добавить();
			
			Реквизит.Заголовок = ОписаниеПоля.Заголовок;
			Если ОписаниеПоля.Родитель <> Неопределено И СтрНачинаетсяС(Реквизит.Заголовок, ОписаниеПоля.Родитель.Заголовок) Тогда
				Реквизит.Заголовок = Сред(Реквизит.Заголовок, СтрДлина(ОписаниеПоля.Родитель.Заголовок) + 2);
			КонецЕсли;
			
			Реквизит.Поле = ОписаниеПоля.Поле;
			Реквизит.Имя = ИмяПоля(ОписаниеПоля.Поле);
			
			Если Не ОписаниеПоля.Тип.СодержитТип(Тип("ТаблицаЗначений")) Тогда
				Реквизит.Тип = ОписаниеПоля.Тип;
			КонецЕсли;
			
			Реквизит.Папка = ОписаниеПоля.Папка;
			Реквизит.Таблица = ОписаниеПоля.Таблица;
			Реквизит.Порядок = 1;
			
			ДополнительныеПараметры = Новый Соответствие;
			Если ТипЗнч(ОписаниеПоля) = Тип("ДоступноеПолеОтбораКомпоновкиДанных") И ЗначениеЗаполнено(ОписаниеПоля.Маска)
				И СтрНачинаетсяС(ОписаниеПоля.Маска, "{") И СтрЗаканчиваетсяНа(ОписаниеПоля.Маска, "}") Тогда
				ДополнительныеПараметры = ОбщегоНазначения.JSONВЗначение(ОписаниеПоля.Маска);
			КонецЕсли;
			
			Если ДополнительныеПараметры["Картинка"] <> Неопределено Тогда
				Реквизит.Картинка = Новый Картинка(Base64Значение(ДополнительныеПараметры["Картинка"]));
			КонецЕсли;
			
			Порядок = ДополнительныеПараметры["Порядок"];
			Если ЗначениеЗаполнено(Порядок) Тогда
				Реквизит.Порядок = Порядок;
			КонецЕсли;
			
			Реквизит.ЭтоГруппа = ДополнительныеПараметры["ЭтоГруппа"];
			Если Реквизит.ЭтоГруппа Тогда
				Реквизит.Папка = Реквизит.ЭтоГруппа;
			КонецЕсли;
			
			Реквизит.ЭтоФункция = ДополнительныеПараметры["ЭтоФункция"];
			Реквизит.Скрытый = ДополнительныеПараметры["Скрытый"];
			Реквизит.ВыражениеДляВставки = ДополнительныеПараметры["ВыражениеДляВставки"];
			
			Если Не ЗначениеЗаполнено(Реквизит.Картинка) Тогда
				Реквизит.Картинка = КартинкаТипа(ОписаниеПоля.Тип);
				
				Если Реквизит.Таблица Тогда
					Реквизит.Картинка = БиблиотекаКартинок.ТипСписок;
				ИначеЕсли Реквизит.Папка Тогда
					Реквизит.Картинка = БиблиотекаКартинок.ТипПапка;
				ИначеЕсли ЭтоРеквизитКартинка(Реквизит, ПрефиксыПолейКартинка, ТипыПрисоединенныхФайлов) Тогда
					Реквизит.Картинка = БиблиотекаКартинок.ТипКартинка;
				ИначеЕсли СтрНачинаетсяС(Реквизит.Имя, "Штамп") Тогда
					Реквизит.Картинка = БиблиотекаКартинок.ШтампЭлектроннойПодписи;
				КонецЕсли;
			КонецЕсли;
			
			Если ОписаниеПоля.Поле = Новый ПолеКомпоновкиДанных("СистемныеПоля") Тогда
				Реквизит.Порядок = 2;
			КонецЕсли;
			Если ОписаниеПоля.Поле = Новый ПолеКомпоновкиДанных("ПользовательскиеПоля") Тогда
				Реквизит.Заголовок = НСтр("ru = 'Формулы'");
				Реквизит.Картинка = БиблиотекаКартинок.ТипФункция;
				Реквизит.Порядок = 3;
			КонецЕсли;
			Если ОписаниеПоля.Поле = Новый ПолеКомпоновкиДанных("ДетальныеЗаписи") Тогда
				Реквизит.Порядок = 4;
			КонецЕсли;
			Если ОписаниеПоля.Поле = Новый ПолеКомпоновкиДанных("ОбщиеРеквизиты") Тогда
				Реквизит.Порядок = 5;
			КонецЕсли;
			
			Реквизит.ПредставлениеПутиКДанным = "";
			Если Не Реквизит.ЭтоГруппа Тогда
				Реквизит.ПутьКДанным = Реквизит.Имя;
				Реквизит.ПредставлениеПутиКДанным = Реквизит.Заголовок;
			КонецЕсли;
			
			ЕстьПодчиненные = Реквизит.ЭтоГруппа Или ЕстьПодчиненныеЭлементы(ОписаниеПоля);
			Если ЕстьПодчиненные Тогда
				Реквизит.ЕстьПодчиненные = Истина;
			КонецЕсли;
			
		КонецЦикла;
	КонецЦикла;
	
	ДоступныеРеквизиты.Сортировать("Порядок, Заголовок");
	Возврат ДоступныеРеквизиты;
	
КонецФункции

Функция ЭтоСлужебноеПоле(Знач ОписаниеПоля, Знач СлужебныеПоля)

	ИмяПоля = Строка(ОписаниеПоля.Поле);
	Если ОписаниеПоля.Таблица И СлужебныеПоля[ИмяПоля] = Истина Тогда
		Возврат Истина;
	КонецЕсли;
	Для каждого СлужебноеПоле Из СлужебныеПоля Цикл
		Если СтрЗаканчиваетсяНа(ИмяПоля, "." + СлужебноеПоле.Ключ) Тогда	
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат (СтрЗаканчиваетсяНа(ИмяПоля, ".ВерсияДанных"));

КонецФункции

Функция СлужебныеПоля()
	Результат = Новый Соответствие;
	Результат["ДополнительныеРеквизиты"] = Истина;
	Результат["КонтактнаяИнформация"] = Истина;
	Результат["Представления"] = Истина;
	Возврат Результат;
КонецФункции	

Функция ЭтоРеквизитКартинка(Реквизит, ПрефиксыПолейКартинка, ТипыПрисоединенныхФайлов)

	Для каждого ПрефиксПоля Из ПрефиксыПолейКартинка Цикл
		Если СтрНачинаетсяС(Реквизит.Имя, "." + ПрефиксПоля.Ключ) Тогда	
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;

 	Возврат Реквизит.Тип.Типы().Количество() = 1 И ТипыПрисоединенныхФайлов.СодержитТип(Реквизит.Тип.Типы()[0]);
		
КонецФункции

Функция ПрефиксыПолейКартинка()
	Результат = Новый Соответствие;
	Результат["Подпись"] = Истина;
	Результат["Факсимиле"] = Истина;
	Результат["Картинка"] = Истина;
	Возврат Результат;
КонецФункции	
	
Функция ТипыПрисоединенныхФайлов()
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами") Тогда
		МодульРаботаСФайламиСлужебный = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебный");
		Возврат МодульРаботаСФайламиСлужебный.ТипыПрисоединенныхФайлов();
	КонецЕсли;
	Возврат Новый ОписаниеТипов();
	
КонецФункции	

// Возвращаемое значение:
//  ТаблицаЗначений:
//   * Имя - Строка
//   * Заголовок - Строка
//   * Поле - ПолеКомпоновкиДанных
//   * ПутьКДанным - Строка
//   * ПредставлениеПутиКДанным - Строка
//   * Тип - ОписаниеТипов
//   * Картинка - Картинка
//   * Папка - Булево
//   * Таблица - Булево
//   * СвойНаборПолей - Булево 
//   * Отступ - Строка
//   * СоответствуетОтбору - Булево
//   * ПодчиненныйЭлементСоответствуетОтбору - Булево
//   * ЭтоГруппа - Булево
//   * Скрытый - Булево
//   * ВыражениеДляВставки - Строка
//
Функция НоваяКоллекцияДоступныхРеквизитов() 
	
	ДоступныеРеквизиты = Новый ТаблицаЗначений;
	Для Каждого ОписаниеРеквизита Из РеквизитыПодключаемогоСписка() Цикл
		ИмяРеквизита = ОписаниеРеквизита.Ключ;
		ТипРеквизита = ОписаниеРеквизита.Значение;
		ДоступныеРеквизиты.Колонки.Добавить(ИмяРеквизита, ТипРеквизита);
	КонецЦикла;
	
	Возврат ДоступныеРеквизиты;
	
КонецФункции

// Параметры:
//  Коллекция - ДанныеФормыДерево
//            - ДанныеФормыКоллекцияЭлементовДерева
//            - ДеревоЗначений
//            - СтрокаДереваЗначений
//
Функция ПодчиненныеЭлементы(Коллекция)
	
	Если ТипЗнч(Коллекция) = Тип("ДеревоЗначений") Или ТипЗнч(Коллекция) = Тип("СтрокаДереваЗначений") Тогда
		Возврат Коллекция.Строки;
	КонецЕсли;
	
	Возврат Коллекция.ПолучитьЭлементы();
	
КонецФункции

// Параметры:
//  Элемент - ДанныеФормыДерево
//          - ДанныеФормыКоллекцияЭлементовДерева
//          - ДеревоЗначений
//          - СтрокаДереваЗначений
//
Функция Родитель(Элемент)
	
	Если ТипЗнч(Элемент) = Тип("ДанныеФормыЭлементДерева") Тогда
		Возврат Элемент.ПолучитьРодителя();
	ИначеЕсли ТипЗнч(Элемент) = Тип("СтрокаДереваЗначений") Тогда
		Возврат Элемент.Родитель;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

Функция НайтиПоИдентификатору(Коллекция, ИдентификаторСтроки)
	
	Если ТипЗнч(Коллекция) = Тип("ДеревоЗначений") Или ТипЗнч(Коллекция) = Тип("СтрокаДереваЗначений") Тогда
		Возврат Коллекция.Строки.Найти(ИдентификаторСтроки, "Идентификатор", Истина);
	КонецЕсли;
	
	Возврат Коллекция.НайтиПоИдентификатору(ИдентификаторСтроки);
	
КонецФункции

// Возвращаемое значение:
//  Массив из ДоступныеПоляКомпоновкиДанных
//
Функция КоллекцииДоступныхПолей(Реквизит, ИсточникиДоступныхПолей, НастройкиСписка, УникальныйИдентификаторФормы)
	
	Результат = Новый Массив;
	
	Если ТипЗнч(Реквизит) = Тип("ДанныеФормыДерево") Или ТипЗнч(Реквизит) = Тип("ДеревоЗначений") Тогда
		Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей Цикл
			Результат.Добавить(ИсточникДоступныхПолей.КоллекцияПолей);
		КонецЦикла;
		Возврат Результат;
	КонецЕсли;
	
	Замещать = Ложь;
	Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей(ИсточникиДоступныхПолей, НастройкиСписка, Реквизит, УникальныйИдентификаторФормы) Цикл
		Реквизит.СвойНаборПолей = Истина;
		Результат.Добавить(ИсточникДоступныхПолей.КоллекцияПолей);
		Замещать = Замещать Или ИсточникДоступныхПолей.Замещать;
	КонецЦикла;
	
	Если Замещать И ЗначениеЗаполнено(Результат) Тогда
		Возврат Результат;
	КонецЕсли;
	
	Родитель = Родитель(Реквизит);
	Пока Родитель <> Неопределено Цикл
		Если Родитель.СвойНаборПолей Тогда
			Прервать;
		Иначе
			Родитель = Родитель(Родитель);
			Продолжить;
		КонецЕсли;
	КонецЦикла;
	
	Если Родитель <> Неопределено Тогда
		Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей(ИсточникиДоступныхПолей, НастройкиСписка, Родитель, УникальныйИдентификаторФормы) Цикл
			Поле = ИсточникДоступныхПолей.КоллекцияПолей.НайтиПоле(Реквизит.Поле);
			Если Поле <> Неопределено Тогда
				Результат.Добавить(Поле);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Если ЗначениеЗаполнено(Результат) И Реквизит.Поле = Новый ПолеКомпоновкиДанных("Номер") Тогда
		Возврат Результат;
	КонецЕсли;
	
	Если Не Замещать Или Не ЗначениеЗаполнено(Результат) Тогда
		Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей(ИсточникиДоступныхПолей, НастройкиСписка, ,УникальныйИдентификаторФормы) Цикл
			Поле = ИсточникДоступныхПолей.КоллекцияПолей.НайтиПоле(Реквизит.Поле);
			Если Поле <> Неопределено Тогда
				Результат.Добавить(Поле);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

Функция ИсточникиДоступныхПолей(ИсточникиДоступныхПолей, НастройкиСписка, Реквизит = Неопределено, УникальныйИдентификаторФормы = Неопределено)
	
	Результат = Новый Массив;
	ИмяОсновногоИсточникаДанных = ИмяОсновногоИсточникаДанных(ИсточникиДоступныхПолей);

	Если Реквизит = Неопределено Тогда
		Отбор = Новый Структура("ИсточникДанных", ИмяОсновногоИсточникаДанных);
		Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей.НайтиСтроки(Отбор) Цикл
			Результат.Добавить(ИсточникДоступныхПолей);
		КонецЦикла;
		Возврат Результат;
	КонецЕсли;
	
	ИсточникиДанных = Новый Массив;
	
	Родитель = Родитель(Реквизит);
	Пока Родитель <> Неопределено И Родитель.Папка Цикл
		Родитель = Родитель(Родитель);
	КонецЦикла;
	
	Если Родитель = Неопределено Тогда
		Если ЗначениеЗаполнено(ИмяОсновногоИсточникаДанных) Тогда
			ИсточникДанных = ИмяОсновногоИсточникаДанных + "." + Реквизит.Имя;
			ИсточникиДанных.Добавить(ИсточникДанных);
		КонецЕсли;
	Иначе
		Для Каждого Тип Из Родитель.Тип.Типы() Цикл
			Если Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")
				Или Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда
				Продолжить;
			КонецЕсли;
			ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
			Если ОбъектМетаданных = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			ИсточникДанных = ОбъектМетаданных.ПолноеИмя() + "." + Реквизит.Имя;
			ИсточникиДанных.Добавить(ИсточникДанных);
		КонецЦикла;
	КонецЕсли;
	
	МассивМетаданныхПеречислений = КонструкторФормулПовтИсп.МетаданныеПеречислений();
	
	Для Каждого Тип Из Реквизит.Тип.Типы() Цикл
		Если Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовМетаданных")
			Или Тип = Тип("СправочникСсылка.ИдентификаторыОбъектовРасширений") Тогда
			Продолжить;
		КонецЕсли;
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
		Если ОбъектМетаданных = Неопределено Или МассивМетаданныхПеречислений.Найти(ОбъектМетаданных) <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		ИсточникДанных = ОбъектМетаданных.ПолноеИмя();
		ИсточникиДанных.Добавить(ИсточникДанных);
	КонецЦикла;
	
	Для Каждого ИсточникДанных Из ИсточникиДанных Цикл
		ИсточникНайден = Ложь;
		Для Каждого ИсточникДоступныхПолей Из ИсточникиДоступныхПолей Цикл
			Если СтрокаСоответствуетШаблону(ИсточникДанных, ИсточникДоступныхПолей.ИсточникДанных) Тогда
				Результат.Добавить(ИсточникДоступныхПолей);
				ИсточникНайден = Истина;
				Продолжить;
			КонецЕсли;
		КонецЦикла;
		
		Если Не ИсточникНайден И НастройкиСписка <> Неопределено
			И ЗначениеЗаполнено(НастройкиСписка.ПриОпределенииИсточниковДоступныхПолей) Тогда
			
			ИсточникиПолей = КоллекцияИсточниковДоступныхПолей();
			Модуль = ОбщегоНазначения.ОбщийМодуль(НастройкиСписка.ПриОпределенииИсточниковДоступныхПолей);
			Модуль.ПриОпределенииИсточниковДоступныхПолей(ИсточникДанных, Реквизит.Тип, ИсточникиПолей, УникальныйИдентификаторФормы);
			
			Если ЗначениеЗаполнено(ИсточникиПолей) Тогда
				Для Каждого ИсточникПолей Из ИсточникиПолей Цикл
					ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить();
					ЗаполнитьЗначенияСвойств(ИсточникДоступныхПолей, ИсточникПолей);
					Результат.Добавить(ИсточникДоступныхПолей);
				КонецЦикла;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если ЗначениеЗаполнено(Результат) Тогда
		Возврат Результат;
	КонецЕсли;
	
	Для Каждого Тип Из Реквизит.Тип.Типы() Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
		Если ОбъектМетаданных = Неопределено Или Метаданные.Перечисления.Содержит(ОбъектМетаданных) Тогда
			Продолжить;
		КонецЕсли;
		ИсточникДанных = ОбъектМетаданных.ПолноеИмя();
		
		ИспользоватьИдентификаторыДляФормул = Ложь;
		Если НастройкиСписка <> Неопределено Тогда
			ИспользоватьИдентификаторыДляФормул = НастройкиСписка.ИспользоватьИдентификаторыДляФормул;
		КонецЕсли;
		
		Если ИспользоватьИдентификаторыДляФормул Тогда
			КомпоновщикНастроек = КомпоновщикНастроекОбъекта(ОбъектМетаданных);
			ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить();
			ИсточникДоступныхПолей.ИсточникДанных = ИсточникДанных;
			ИсточникДоступныхПолей.КоллекцияПолей = КомпоновщикНастроек.Настройки.ДоступныеПоляОтбора;
			ИсточникДоступныхПолей.Замещать = Истина;
			
			Результат.Добавить(ИсточникДоступныхПолей);
			
			КоллекцияПолей = КоллекцияДопРеквизитов(ОбъектМетаданных.ПолноеИмя());
			Если КоллекцияПолей <> Неопределено Тогда
				ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить();
				ИсточникДоступныхПолей.ИсточникДанных = ИсточникДанных;
				ИсточникДоступныхПолей.КоллекцияПолей = КоллекцияПолей;
				
				Результат.Добавить(ИсточникДоступныхПолей);
			КонецЕсли;
			
			КоллекцияПолей = КоллекцияПолейКонтактнойИнформации(ОбъектМетаданных.ПолноеИмя());
			Если КоллекцияПолей <> Неопределено Тогда
				ИсточникДоступныхПолей = ИсточникиДоступныхПолей.Добавить();
				ИсточникДоступныхПолей.ИсточникДанных = ИсточникДанных;
				ИсточникДоступныхПолей.КоллекцияПолей = КоллекцияПолей;
				
				Результат.Добавить(ИсточникДоступныхПолей);
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция СтрокаСоответствуетШаблону(Знач Строка, Знач Шаблон)
	
	Если Не ЗначениеЗаполнено(Шаблон) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Если Не СтрЧислоВхождений(Шаблон, "*") Тогда
		Возврат Строка = Шаблон;
	КонецЕсли;
	
	Строка = СтрСоединить(СтрРазделить(Строка, " " + Символы.ПС + Символы.ВК + Символы.Таб, Ложь), " ");
	СтрокаСоответствуетШаблону = Истина;
	
	Для Каждого ЧастиШаблона Из СтрРазделить(Шаблон, "*", Истина) Цикл
		ФрагментДляПоиска = СтрСоединить(СтрРазделить(ЧастиШаблона, " " + Символы.ПС + Символы.ВК + Символы.Таб, Ложь), " ");

		Если Не ЗначениеЗаполнено(Строка) И ФрагментДляПоиска = "" Тогда
			СтрокаСоответствуетШаблону = Ложь;
			Прервать;
		КонецЕсли;
		
		Позиция = СтрНайти(Строка, ФрагментДляПоиска);
		Если Позиция = 0 Тогда
			СтрокаСоответствуетШаблону = Ложь;
			Прервать;
		КонецЕсли;
		
		Строка = Сред(Строка, Позиция + СтрДлина(ФрагментДляПоиска));
	КонецЦикла;
	
	Если Не СтрЗаканчиваетсяНа(Шаблон, "*") И ЗначениеЗаполнено(Строка) Тогда
		СтрокаСоответствуетШаблону = Ложь;
	КонецЕсли;
	
	Возврат СтрокаСоответствуетШаблону;
	
КонецФункции

Функция КомпоновщикНастроекОбъекта(ОбъектМетаданных)
	
	СхемаКомпоновкиДанных = Неопределено;
	
	Если ТипЗнч(ОбъектМетаданных) = Тип("Строка") Тогда
		СхемаКомпоновкиДанных = ПолучитьОбщийМакет("ДанныеПечати" + ОбъектМетаданных);
	Иначе
		ЕстьДанныеПечати = ОбъектМетаданных.Макеты.Найти("ДанныеПечати") <> Неопределено;
		Если ЕстьДанныеПечати Тогда
			МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ОбъектМетаданных.ПолноеИмя());
			СхемаКомпоновкиДанных = МенеджерОбъекта.ПолучитьМакет("ДанныеПечати");
		Иначе
			ТекстЗапроса = ТекстЗапроса(ОбъектМетаданных.ПолноеИмя());
			СхемаКомпоновкиДанных = СхемаКомпоновкиДанных(ТекстЗапроса);
		КонецЕсли;
	КонецЕсли;
	
	ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(СхемаКомпоновкиДанных);
	
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
	КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
	
	Возврат КомпоновщикНастроек;
	
КонецФункции

Функция СхемаКомпоновкиДанных(ТекстЗапроса)
	
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
	ИсточникДанных.Имя = "ИсточникДанных1";
	ИсточникДанных.ТипИсточникаДанных = "local";
	
	НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхЗапросСхемыКомпоновкиДанных"));
	НаборДанных.ИсточникДанных = "ИсточникДанных1";
	НаборДанных.АвтоЗаполнениеДоступныхПолей = Истина;
	НаборДанных.Запрос = ТекстЗапроса;
	НаборДанных.Имя = "НаборДанных1";
	
	Возврат СхемаКомпоновкиДанных;
	
КонецФункции

Функция ТекстЗапроса(ТипыИзменяемыхОбъектов, ОграничитьВыборку = Ложь)
	
	ОбъектыМетаданных = Новый Массив;
	Для Каждого ИмяОбъекта Из СтрРазделить(ТипыИзменяемыхОбъектов, ",", Ложь) Цикл
		ОбъектыМетаданных.Добавить(ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта));
	КонецЦикла;
	
	СтруктураОбъектов = ОбщиеРеквизитыОбъектов(ТипыИзменяемыхОбъектов);
	
	Результат = "";
	ПсевдонимТаблицы = "ПсевдонимЗаданнойТаблицы";
	Для Каждого ОбъектМетаданных Из ОбъектыМетаданных Цикл
		
		Если Не ПустаяСтрока(Результат) Тогда
			Результат = Результат + Символы.ПС + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС + Символы.ПС;
		КонецЕсли;
		
		ТекстЗапроса = "";
		
		Для Каждого ИмяРеквизита Из СтруктураОбъектов.Реквизиты Цикл
			Если Не ПустаяСтрока(ТекстЗапроса) Тогда
				ТекстЗапроса = ТекстЗапроса + "," + Символы.ПС;
			КонецЕсли;
			ТекстЗапроса = ТекстЗапроса + ПсевдонимТаблицы + "." + ИмяРеквизита + " КАК " + ИмяРеквизита;
		КонецЦикла;
		
		Для Каждого ТабличнаяЧасть Из СтруктураОбъектов.ТабличныеЧасти Цикл
			ИмяТабличнойЧасти = ТабличнаяЧасть.Ключ;
			ТекстЗапроса = ТекстЗапроса + "," + Символы.ПС + ПсевдонимТаблицы + "." + ИмяТабличнойЧасти + ".(";
			
			СтрокаРеквизитов = "НомерСтроки";
			РеквизитыТабличнойЧасти = ТабличнаяЧасть.Значение;
			Для Каждого ИмяРеквизита Из РеквизитыТабличнойЧасти Цикл
				Если Не ПустаяСтрока(СтрокаРеквизитов) Тогда
					СтрокаРеквизитов = СтрокаРеквизитов + "," + Символы.ПС;
				КонецЕсли;
				СтрокаРеквизитов = СтрокаРеквизитов + ИмяРеквизита;
			КонецЦикла;
			ТекстЗапроса = ТекстЗапроса + СтрокаРеквизитов +"
			|)";
		КонецЦикла;
		
		ТекстЗапроса = "ВЫБРАТЬ " + ?(ОграничитьВыборку, "ПЕРВЫЕ 1001 ", "") //@query-part
			+ ТекстЗапроса + Символы.ПС + "
			|ИЗ
			|	"+ ОбъектМетаданных.ПолноеИмя() + " КАК " + ПсевдонимТаблицы;
		
		Результат = Результат + ТекстЗапроса;
	КонецЦикла;
		
		
	Возврат Результат;
	
КонецФункции

Функция ОбщиеРеквизитыОбъектов(ТипыОбъектов) Экспорт
	
	ОбъектыМетаданных = Новый Массив;
	Для Каждого ИмяОбъекта Из СтрРазделить(ТипыОбъектов, ",", Ложь) Цикл
		ОбъектыМетаданных.Добавить(ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъекта));
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("Реквизиты", Новый Массив);
	Результат.Вставить("ТабличныеЧасти", Новый Структура);
	
	Если ОбъектыМетаданных.Количество() = 0 Тогда
		Возврат Результат;
	КонецЕсли;
		
	ОбщийСписокРеквизитов = СписокЭлементов(ОбъектыМетаданных[0].Реквизиты, Ложь);
	Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
		ОбщийСписокРеквизитов = ПересечениеРеквизитов(ОбщийСписокРеквизитов, ОбъектыМетаданных[Индекс].Реквизиты);
	КонецЦикла;
	
	СтандартныеРеквизиты = ОбъектыМетаданных[0].СтандартныеРеквизиты;
	Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
		СтандартныеРеквизиты = ПересечениеРеквизитов(СтандартныеРеквизиты, ОбъектыМетаданных[Индекс].СтандартныеРеквизиты);
	КонецЦикла;
	Для Каждого Реквизит Из СтандартныеРеквизиты Цикл
		ОбщийСписокРеквизитов.Добавить(Реквизит);
	КонецЦикла;
	
	Результат.Реквизиты = СписокЭлементов(ОбщийСписокРеквизитов);
	
	ТабличныеЧасти = СписокЭлементов(ОбъектыМетаданных[0].ТабличныеЧасти);
	Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
		ТабличныеЧасти = ПересечениеМножеств(ТабличныеЧасти, СписокЭлементов(ОбъектыМетаданных[Индекс].ТабличныеЧасти));
	КонецЦикла;
	
	Для Каждого ИмяТабличнойЧасти Из ТабличныеЧасти Цикл
		РеквизитыТабличнойЧасти = СписокЭлементов(ОбъектыМетаданных[0].ТабличныеЧасти[ИмяТабличнойЧасти].Реквизиты, Ложь);
		Для Индекс = 1 По ОбъектыМетаданных.Количество() - 1 Цикл
			РеквизитыТабличнойЧасти = ПересечениеРеквизитов(РеквизитыТабличнойЧасти, ОбъектыМетаданных[Индекс].ТабличныеЧасти[ИмяТабличнойЧасти].Реквизиты);
		КонецЦикла;
		Если РеквизитыТабличнойЧасти.Количество() > 0 Тогда
			Результат.ТабличныеЧасти.Вставить(ИмяТабличнойЧасти, СписокЭлементов(РеквизитыТабличнойЧасти));
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПересечениеМножеств(Множество1, Множество2) Экспорт
	
	Результат = Новый Массив;
	
	Для Каждого Элемент Из Множество2 Цикл
		Индекс = Множество1.Найти(Элемент);
		Если Индекс <> Неопределено Тогда
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

Функция ПересечениеРеквизитов(КоллекцияРеквизитов1, КоллекцияРеквизитов2)
	
	Результат = Новый Массив;
	
	Для Каждого Реквизит2 Из КоллекцияРеквизитов2 Цикл
		Для Каждого Реквизит1 Из КоллекцияРеквизитов1 Цикл
			Если Реквизит1.Имя = Реквизит2.Имя 
				И (Реквизит1.Тип = Реквизит2.Тип Или Реквизит1.Имя = "Ссылка") Тогда
				Результат.Добавить(Реквизит1);
				Прервать;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Результат;
	
КонецФункции

// Параметры:
//   Коллекция - Массив из ОбъектМетаданныхРеквизит
//             - Массив из ОбъектМетаданныхТабличнаяЧасть
//   ТолькоИмена - Булево
// Возвращаемое значение:
//   Массив
//
Функция СписокЭлементов(Коллекция, ТолькоИмена = Истина)
	Результат = Новый Массив;
	Для Каждого Элемент Из Коллекция Цикл
		Если ТолькоИмена Тогда
			Результат.Добавить(Элемент.Имя);
		Иначе
			Результат.Добавить(Элемент);
		КонецЕсли;
	КонецЦикла;
	Возврат Результат;
КонецФункции

Процедура ЗаполнитьСписокДоступныхПолей(Форма, ПараметрыЗаполнения) Экспорт
	
	ИдентификаторСтроки = ПараметрыЗаполнения.ИдентификаторСтроки;
	ИмяСписка = ПараметрыЗаполнения.ИмяСписка;
	
	РазвернутьРеквизит(ИдентификаторСтроки, ИмяСписка, Форма);
	
КонецПроцедуры

Функция СписокИсточниковДоступныхПолей(Форма, ИмяСпискаПолей)
	
	ИмяСпискаИсточников = КонструкторФормулКлиентСервер.НастройкиСпискаПолей(Форма, ИмяСпискаПолей).ИмяСпискаИсточников;
	Возврат Форма[ИмяСпискаИсточников];
	
КонецФункции

Функция СписокСвойствДляВидаОбъектов(ВидОбъектов)
	Результат = Новый Массив;
	
	ВидыСвойств = Новый Массив;
	ВидыСвойств.Добавить("ДополнительныеРеквизиты");
	ВидыСвойств.Добавить("ДополнительныеСведения");
	
	МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
	Если МодульУправлениеСвойствамиСлужебный <> Неопределено Тогда
		Для Каждого ВидСвойства Из ВидыСвойств Цикл
			СписокСвойств = МодульУправлениеСвойствамиСлужебный.СписокСвойствДляВидаОбъектов(ВидОбъектов, ВидСвойства);
			Если СписокСвойств <> Неопределено Тогда
				Для Каждого Элемент Из СписокСвойств Цикл
					Результат.Добавить(Элемент.Свойство);
				КонецЦикла;
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Возврат Результат;
КонецФункции

Функция КоллекцияДопРеквизитов(ИмяОбъектаМетаданных)
	
	СписокСвойств = СписокСвойствДляВидаОбъектов(ИмяОбъектаМетаданных);
	Если Не ЗначениеЗаполнено(СписокСвойств) Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ЗначенияРеквизитов = ОбщегоНазначения.ЗначенияРеквизитовОбъектов(СписокСвойств, "Заголовок,ИдентификаторДляФормул,ТипЗначения");
	
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
	ИсточникДанных.Имя = "ИсточникДанных1";
	ИсточникДанных.ТипИсточникаДанных = "local";
	
	НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
	НаборДанных.ИсточникДанных = "ИсточникДанных1";
	НаборДанных.Имя = "НаборДанных1";
	
	Для Каждого Элемент Из ЗначенияРеквизитов Цикл
		Свойство = Элемент.Значение;
		Поле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
		Поле.Поле = Свойство.ИдентификаторДляФормул;
		Поле.ПутьКДанным = Свойство.ИдентификаторДляФормул;
		Если ЗначениеЗаполнено(Свойство.Заголовок) Тогда
			Поле.Заголовок = Свойство.Заголовок;
		КонецЕсли;
		Поле.ТипЗначения = Свойство.ТипЗначения;
	КонецЦикла;
	
	АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных);
	ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы);
	
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
	КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
	
	Возврат КомпоновщикНастроек.Настройки.ДоступныеПоляОтбора;
	
КонецФункции

Функция КоллекцияПолейКонтактнойИнформации(ИмяОбъектаМетаданных)
	
	ВидыКонтактнойИнформации = Неопределено;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");

		ВидыКонтактнойИнформации = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(
			ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ИмяОбъектаМетаданных).ПустаяСсылка());
	КонецЕсли;
	
	Если Не ЗначениеЗаполнено(ВидыКонтактнойИнформации) Тогда
		Возврат Неопределено;
	КонецЕсли;
		
	СхемаКомпоновкиДанных = Новый СхемаКомпоновкиДанных;
	
	ИсточникДанных = СхемаКомпоновкиДанных.ИсточникиДанных.Добавить();
	ИсточникДанных.Имя = "ИсточникДанных1";
	ИсточникДанных.ТипИсточникаДанных = "local";
	
	НаборДанных = СхемаКомпоновкиДанных.НаборыДанных.Добавить(Тип("НаборДанныхОбъектСхемыКомпоновкиДанных"));
	НаборДанных.ИсточникДанных = "ИсточникДанных1";
	НаборДанных.Имя = "НаборДанных1";
	
	Для Каждого ВидКонтактнойИнформации Из ВидыКонтактнойИнформации Цикл
		Если Не ЗначениеЗаполнено(ВидКонтактнойИнформации.ИдентификаторДляФормул) Тогда
			Продолжить;
		КонецЕсли;
		Поле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
		Поле.Поле = ВидКонтактнойИнформации.ИдентификаторДляФормул;
		Поле.ПутьКДанным = ВидКонтактнойИнформации.ИдентификаторДляФормул;
		Если ЗначениеЗаполнено(ВидКонтактнойИнформации.Наименование) Тогда
			Поле.Заголовок = ВидКонтактнойИнформации.Наименование;
		КонецЕсли;
		Поле.ТипЗначения = Новый ОписаниеТипов("Строка");
	КонецЦикла;
	
	АдресСхемы = ПоместитьВоВременноеХранилище(СхемаКомпоновкиДанных);
	ИсточникДоступныхНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(АдресСхемы);
	
	КомпоновщикНастроек = Новый КомпоновщикНастроекКомпоновкиДанных;
	КомпоновщикНастроек.Инициализировать(ИсточникДоступныхНастроек);
	КомпоновщикНастроек.ЗагрузитьНастройки(СхемаКомпоновкиДанных.НастройкиПоУмолчанию);
	
	Возврат КомпоновщикНастроек.Настройки.ДоступныеПоляОтбора;
	
КонецФункции

Процедура ВыполнитьПоискВСпискеПолей(Форма) Экспорт
	
	ИмяСпискаПолей = ИмяРеквизитаСпискаПолей(Форма.ИмяТекущейСтрокиПоиска);
	ИмяРеквизитаСтрокиПоиска = Форма.ИмяТекущейСтрокиПоиска;
	Отбор = Форма[ИмяРеквизитаСтрокиПоиска];
	ОтборУстановлен = ЗначениеЗаполнено(Отбор);
	Если ЗначениеЗаполнено(Отбор) Тогда
		УстановитьОтбор(Форма, ИмяСпискаПолей, Отбор, Форма[ИмяСпискаПолей]);
	КонецЕсли;
	Форма.Элементы[ИмяСпискаПолей + "Представление"].Видимость = НЕ ОтборУстановлен;
	Форма.Элементы[ИмяСпискаПолей + "ПредставлениеПутиКДанным"].Видимость = ОтборУстановлен;
	Форма.Элементы[ИмяСпискаПолей].Отображение = ?(ОтборУстановлен, ОтображениеТаблицы.Список, ОтображениеТаблицы.Дерево);
	
КонецПроцедуры

Процедура УстановитьОтбор(Знач Форма, Знач ИмяСписка, Знач Отбор,
	Знач КоллекцияРеквизитов = Неопределено, Знач Уровень = 0)
	
	ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание();
	ЭтоФоновоеЗадание = (ТекущийСеанс <> Неопределено);
	
	КоличествоВПорции = 10;
	МаксимальноеКоличествоРезультатов = 200;
	МаксимальныйУровеньПоиска = ?(ЭтоФоновоеЗадание, 3, 2);
	ДостигнутоМаксимальноеКоличествоРезультатов = Ложь;
	
	СтруктураОтбора = Новый Структура("СоответствуетОтбору", Истина);
	Уровень = 1;					   
	КоличествоНайденных = 0;
	ОписаниеТипаВсеСсылки = ОбщегоНазначения.ОписаниеТипаВсеСсылки();
	
	СтрокиПорции = Новый Массив;
	ВсеНайденныеСтроки = Новый Массив;
	Пока Истина Цикл	
		ИспользованныеУзлы = Новый Соответствие;
		Пока Истина Цикл
			ПорцияПолейТекущегоУровня = ПолучитьПорциюПолейЗаданногоУровня(КоллекцияРеквизитов, Уровень, ИспользованныеУзлы,  ИмяСписка, Форма);
			Если ПорцияПолейТекущегоУровня = Неопределено Тогда
				Прервать;
			КонецЕсли;
			УстановитьПризнакОтбора(КоличествоНайденных, МаксимальноеКоличествоРезультатов, ПорцияПолейТекущегоУровня, Отбор);
			Если КоличествоНайденных = МаксимальноеКоличествоРезультатов Тогда
				ДостигнутоМаксимальноеКоличествоРезультатов = Истина;
				Прервать;	
			КонецЕсли;
			Если ЭтоФоновоеЗадание Тогда
				МассивНайденныхЭлементов = ПорцияПолейТекущегоУровня.Строки.НайтиСтроки(СтруктураОтбора, Истина);
				Если МассивНайденныхЭлементов.Количество()  <> 0 Тогда
					Для Каждого НайденныйЭлемент Из МассивНайденныхЭлементов Цикл
						СтруктураСтроки = СтрокуДереваВСтруктуру(НайденныйЭлемент, КоллекцияРеквизитов);
						СтрокиПорции.Добавить(СтруктураСтроки);
						ВсеНайденныеСтроки.Добавить(СтруктураСтроки);
						Если СтрокиПорции.Количество() = КоличествоВПорции Тогда
							ОтправитьПорциюНайденных(СтрокиПорции, ОписаниеТипаВсеСсылки);
						КонецЕсли;
					КонецЦикла;
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		
		Если Уровень > 1 Тогда 
			Если ЭтоФоновоеЗадание Тогда
				ОтправитьПорциюНайденных(СтрокиПорции, ОписаниеТипаВсеСсылки);
			КонецЕсли;
		КонецЕсли;
		
		Уровень = Уровень + 1;
		Если ДостигнутоМаксимальноеКоличествоРезультатов Или Уровень > МаксимальныйУровеньПоиска  Тогда
			Прервать;
		КонецЕсли;
		
	КонецЦикла;
	
	Если ЭтоФоновоеЗадание Тогда
		ОтправитьПорциюНайденных(ВсеНайденныеСтроки, ОписаниеТипаВсеСсылки);
	КонецЕсли;
	
КонецПроцедуры

Процедура ОтправитьПорциюНайденных(НайденныеСтроки, ОписаниеТипаВсеСсылки = Неопределено)
	Если ОписаниеТипаВсеСсылки = Неопределено Тогда
		ОписаниеТипаВсеСсылки = ОбщегоНазначения.ОписаниеТипаВсеСсылки();
	КонецЕсли;
	Результат = Новый Структура("НайденныеЭлементы", НайденныеСтроки);
	Результат.Вставить("ОписаниеТипаВсеСсылки", ОписаниеТипаВсеСсылки);
	ОбщегоНазначения.СообщитьПользователю(ОбщегоНазначения.ЗначениеВСтрокуXML(Результат));
	НайденныеСтроки.Очистить();
КонецПроцедуры

Функция СтрокуДереваВСтруктуру(СтрокаДерева, Дерево)
	
	Колонки = Новый Массив();
	Для Каждого Колонка Из Дерево.Колонки Цикл
		Колонки.Добавить(Колонка.Имя);
	КонецЦикла;
	
	КолонкиСтрокой = СтрСоединить(Колонки, ",");
	
	Результат = Новый Структура(КолонкиСтрокой);
	ЗаполнитьЗначенияСвойств(Результат, СтрокаДерева);
			
	Возврат Результат;
	
КонецФункции

Процедура УстановитьПризнакОтбора(КоличествоНайденных, Знач МаксимальноеКоличествоРезультатов, Знач КоллекцияРеквизитов, Знач Отбор)
	
	Для Каждого Реквизит Из ПодчиненныеЭлементы(КоллекцияРеквизитов) Цикл
		Если КоличествоНайденных = МаксимальноеКоличествоРезультатов Тогда
			Возврат;	
		КонецЕсли;
		Если РодительскийРеквизитСоответствуетОтбору(Реквизит) Тогда
			Реквизит.СоответствуетОтбору = Ложь;
		Иначе
			ФорматированнаяСтрока = НайтиТекстВСтроке(Реквизит.ПредставлениеПутиКДанным, Отбор);
			Реквизит.СоответствуетОтбору = ФорматированнаяСтрока <> Неопределено;
			Если Реквизит.СоответствуетОтбору Тогда
				КоличествоНайденных = КоличествоНайденных + 1;
				Реквизит.ПредставлениеПутиКДанным = ФорматированнаяСтрока;
				РодительРеквизита = Родитель(Реквизит);
				Если РодительРеквизита <> Неопределено Тогда
					РодительРеквизита.ПодчиненныйЭлементСоответствуетОтбору = Истина;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

Функция ПолучитьПорциюПолейЗаданногоУровня(КоллекцияРеквизитов, Уровень, ИспользованныеУзлы,  ИмяСписка, Форма)
	Если Уровень = 1 Тогда
		Если ИспользованныеУзлы.Получить(-1) <> Неопределено Тогда
			Возврат Неопределено;
		Иначе
			ИспользованныеУзлы.Вставить(-1, Истина);
			Возврат КоллекцияРеквизитов;
		КонецЕсли;
	КонецЕсли;
	Возврат ПолучитьКоллекциюУровня(КоллекцияРеквизитов, Уровень, ИспользованныеУзлы,  ИмяСписка, Форма);
КонецФункции    

Функция ПолучитьИдентификатор(Элемент)
	Если ТипЗнч(Элемент) = Тип("ДанныеФормыЭлементДерева") Тогда
		Возврат Элемент.ПолучитьИдентификатор();
	ИначеЕсли ТипЗнч(Элемент) = Тип("СтрокаДереваЗначений") Тогда
		Возврат Элемент.Идентификатор;
	КонецЕсли;
	
	Возврат Неопределено;
КонецФункции

Функция ПолучитьКоллекциюУровня(КоллекцияРеквизитов, Уровень, ИспользованныеУзлы,  ИмяСписка, Форма, ТекущийУровень = 1, ИндексРодителя = "")
	Если Уровень = ТекущийУровень Тогда
		ИдентификаторРеквизита = ИндексРодителя;
		ИспользованныеУзлы.Вставить(ИдентификаторРеквизита, Истина);
		Возврат КоллекцияРеквизитов;
	КонецЕсли;

	ЭлементыКоллекции = ПодчиненныеЭлементы(КоллекцияРеквизитов);
	
	Для Каждого Реквизит Из ЭлементыКоллекции Цикл
		ИдентификаторРеквизита = ПолучитьИдентификатор(Реквизит);
		Если ИспользованныеУзлы.Получить(ИдентификаторРеквизита) = Неопределено Тогда
			Если ЭлементыКоллекции.Количество() = ЭлементыКоллекции.Индекс(Реквизит)+1 Тогда
				РодительКоллекции = Родитель(КоллекцияРеквизитов);
				Если РодительКоллекции <> Неопределено Тогда
					ИспользованныеУзлы.Вставить(ИндексРодителя, Истина);
				КонецЕсли;
			КонецЕсли;
			
			Если Уровень = ТекущийУровень + 1 Тогда
				Если Не Реквизит.СоответствуетОтбору Тогда
					РазвернутьРеквизит(ИдентификаторРеквизита, ИмяСписка, Форма);
				КонецЕсли;
			КонецЕсли;
			 
			Коллекция = ПолучитьКоллекциюУровня(Реквизит, Уровень, ИспользованныеУзлы,  ИмяСписка, Форма, ТекущийУровень + 1, ИдентификаторРеквизита); 		
			
			Если Коллекция <> Неопределено Тогда
				Возврат Коллекция;
			КонецЕсли; 
		КонецЕсли;
	КонецЦикла;
КонецФункции

Функция РодительскийРеквизитСоответствуетОтбору(Реквизит)
	
	Родитель = Родитель(Реквизит);
	
	Если Родитель <> Неопределено Тогда
		Возврат Родитель.СоответствуетОтбору Или РодительскийРеквизитСоответствуетОтбору(Родитель);
	КонецЕсли;
	
	Возврат Ложь;
	
КонецФункции

Процедура РазвернутьРеквизит(ИдентификаторСтроки, ИмяСписка, Форма)
	
	Отбор = Форма[ИмяРеквизитаСтрокиПоискаСпискаПолей(ИмяСписка)];
	
	ТекущиеДанные = НайтиПоИдентификатору(Форма[ИмяСписка], ИдентификаторСтроки);
	КоллекцияРеквизитов = ПодчиненныеЭлементы(ТекущиеДанные);

	НастройкиСписка = КонструкторФормулКлиентСервер.НастройкиСпискаПолей(Форма, ИмяСписка);
	
	Если КоллекцияРеквизитов.Количество() = 0 Или КоллекцияРеквизитов[0].Поле <> Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	КоллекцияРеквизитов.Очистить();
	ИсточникиДоступныхПолей = СписокИсточниковДоступныхПолей(Форма, ИмяСписка);
	Если ТипЗнч(ИсточникиДоступныхПолей) = Тип("Строка") Тогда
		ИсточникиДоступныхПолей = ОбщегоНазначения.ЗначениеИзСтрокиXML(ИсточникиДоступныхПолей);
		ИмяСпискаИсточников = КонструкторФормулКлиентСервер.НастройкиСпискаПолей(Форма, ИмяСписка).ИмяСпискаИсточников;
		Для Каждого СтрокаТаблицы Из ИсточникиДоступныхПолей Цикл
			
			Если СтрокаТаблицы.СхемаКомпоновкиДанных <> Неопределено Тогда
				СтрокаТаблицы.СхемаКомпоновкиДанных = ОбщегоНазначения.ЗначениеИзСтрокиXML(СтрокаТаблицы.СхемаКомпоновкиДанных);
			КонецЕсли;
			
			Контейнер = ОбщегоНазначения.ЗначениеИзСтрокиXML(СтрокаТаблицы.КоллекцияПолей);
			СтрокаТаблицы.КоллекцияПолей = ДоступныеПоляИзКонтейнераСКД(Контейнер);
						
		КонецЦикла;
		Форма[ИмяСпискаИсточников] = ИсточникиДоступныхПолей;
	КонецЕсли;
	
	ЗаполнитьСписокДоступныхРеквизитов(ТекущиеДанные, ИсточникиДоступныхПолей, Отбор, НастройкиСписка);
	Если ТипЗнч(ТекущиеДанные) = Тип("СтрокаДереваЗначений") Тогда
		УстановитьИдентификаторыСтрокДерева(ТекущиеДанные);
	КонецЕсли;
КонецПроцедуры

Процедура РазвернутьПоле(ТекущиеДанные, ИсточникиДоступныхПолей, НастройкиСписка)
	
	КоллекцияРеквизитов = ПодчиненныеЭлементы(ТекущиеДанные);
	
	Если КоллекцияРеквизитов.Количество() = 0 Или КоллекцияРеквизитов[0].Поле <> Неопределено Тогда
		Возврат;
	КонецЕсли;
	КоллекцияРеквизитов.Очистить();
	
	ЗаполнитьСписокДоступныхРеквизитов(ТекущиеДанные, ИсточникиДоступныхПолей, "", НастройкиСписка);
	
КонецПроцедуры

Процедура УстановитьУсловноеОформление(Форма, ИмяСпискаПолей)
	
	УсловноеОформление = Форма.УсловноеОформление;
	
	//
	
	ЭлементОформления = УсловноеОформление.Элементы.Добавить();
	
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + "Картинка");
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + "Представление");
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + "ПредставлениеПутиКДанным");
	
	ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + ".СоответствуетОтбору");
	ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
	ЭлементОтбора.ПравоеЗначение = Ложь;
	
	ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяРеквизитаСтрокиПоискаСпискаПолей(ИмяСпискаПолей));
	ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Заполнено;
	
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Видимость", Ложь);
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Отображать", Ложь);

	//
	
	ЭлементОформления = УсловноеОформление.Элементы.Добавить();
	
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + "Картинка");
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + "Представление");
	ОформляемоеПоле = ЭлементОформления.Поля.Элементы.Добавить();
	ОформляемоеПоле.Поле = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + "ПредставлениеПутиКДанным");
	
	ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
	ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных(ИмяСпискаПолей + ".Скрытый");
	ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.Равно;
	ЭлементОтбора.ПравоеЗначение = Истина;
	
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Видимость", Ложь);
	ЭлементОформления.Оформление.УстановитьЗначениеПараметра("Отображать", Ложь);
	
КонецПроцедуры

Функция НайтиТекстВСтроке(Знач Строка, Знач Текст)
	
	СтрокаПоиска = Строка;
	
	ФорматированныеСтроки = Новый Массив;
	Для Каждого Подстрока Из СтрРазделить(Текст, " ", Ложь) Цикл
		Позиция = СтрНайти(НРег(СтрокаПоиска), НРег(Подстрока));
		Если Позиция = 0 Тогда
			ФорматированныеСтроки = Неопределено;
			Прервать;
		КонецЕсли;
		
		ПодстрокаДоВхождения = Лев(СтрокаПоиска, Позиция - 1);
		ПодстрокаВхождения = Сред(СтрокаПоиска, Позиция, СтрДлина(Подстрока));
		СтрокаПоиска = Сред(СтрокаПоиска, Позиция + СтрДлина(Подстрока));
		
		ФорматированныеСтроки.Добавить(ПодстрокаДоВхождения);
		ФорматированныеСтроки.Добавить(Новый ФорматированнаяСтрока(ПодстрокаВхождения,
			ШрифтыСтиля.ВажнаяНадписьШрифт, ЦветаСтиля.РезультатУспехЦвет));
	КонецЦикла;
	
	Если Не ЗначениеЗаполнено(ФорматированныеСтроки) Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	ФорматированныеСтроки.Добавить(СтрокаПоиска);
	СтрокаСПодсветкой = Новый ФорматированнаяСтрока(ФорматированныеСтроки); // АПК:1356 - можно использовать составную форматированную строку, так как массив строк формируется из переданного в функцию текста.
	
	Возврат СтрокаСПодсветкой;
	
КонецФункции

Процедура ДобавитьГруппуЭлементовВНаборДанных(КоллекцияЭлементов, НаборДанных, Родитель = Неопределено)
	
	Для Каждого Элемент Из КоллекцияЭлементов.Строки Цикл
		ЭтоГруппа = Ложь;
		
		Если Элемент.Папка Тогда
			Поле = НаборДанных.Поля.Добавить(Тип("ПапкаПолейНабораДанныхСхемыКомпоновкиДанных"));
		ИначеЕсли Элемент.Таблица Тогда 
			Поле = НаборДанных.Поля.Добавить(Тип("ВложенныйНаборДанныхСхемыКомпоновкиДанных"));
			Поле.Поле = Элемент.Идентификатор;
		Иначе
			Поле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
			Поле.ТипЗначения = Элемент.ТипЗначения;
			Поле.Поле = Элемент.Идентификатор;
			Если ТипЗнч(Родитель) = Тип("ВложенныйНаборДанныхСхемыКомпоновкиДанных") Тогда
				Поле.Поле = Родитель.ПутьКДанным + "." + Элемент.Идентификатор;
			КонецЕсли;
			ЭтоГруппа = Элемент.Строки.Количество() > 0 И Не ЗначениеЗаполнено(Элемент.ТипЗначения);			
			
			ДополнительныеПараметры = Новый Структура("Порядок,ЭтоГруппа,ЭтоФункция,Скрытый,ВыражениеДляВставки");
			ЗаполнитьЗначенияСвойств(ДополнительныеПараметры, Элемент);
			ДополнительныеПараметры.ЭтоГруппа = ЭтоГруппа;
			ДополнительныеПараметры.Вставить("Картинка", Base64Строка(Элемент.Картинка.ПолучитьДвоичныеДанные()));			

			Поле.ПараметрыРедактирования.УстановитьЗначениеПараметра("Маска", 
				ОбщегоНазначения.ЗначениеВJSON(ДополнительныеПараметры));
		КонецЕсли;
		
		Поле.ПутьКДанным = Элемент.Идентификатор;
		Если Родитель <> Неопределено Тогда
			Поле.ПутьКДанным = Родитель.ПутьКДанным + "." + Поле.ПутьКДанным;
		КонецЕсли;
			
		Если ЗначениеЗаполнено(Элемент.Представление) Тогда
			Поле.Заголовок = Элемент.Представление;
		КонецЕсли;
		
		Если ЗначениеЗаполнено(Элемент.Формат) Тогда
			ЗначениеПараметра = Поле.Оформление.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Формат"));
			Если ЗначениеПараметра <> Неопределено Тогда
				ЗначениеПараметра.Использование = Истина;
				ЗначениеПараметра.Значение = Элемент.Формат;
			КонецЕсли;
		КонецЕсли;
		
		ДобавитьГруппуЭлементовВНаборДанных(Элемент, НаборДанных, Поле);
	КонецЦикла;
	
КонецПроцедуры

#Область ЧтениеФормулы

Функция ФормулаИзПредставления(Форма, ПредставлениеФормулы, ЭкранироватьНеизвестныеФункции = Истина) Экспорт
	
	ЭлементыФормулы = ЭлементыФормулы(ПредставлениеФормулы);
	Выражение = ПредставлениеФормулы;
	ЗаменяемыеЭлементы = Новый Соответствие;
	
	Для Каждого Элемент Из Форма.ПодключенныеСпискиПолей Цикл
		ИмяСпискаПолей = Элемент.ИмяСпискаПолей;
		КоллекцияПолей = Форма[ИмяСпискаПолей];
		СкобкиИдентификаторов = Элемент.СкобкиИдентификаторов;
		
		Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
			ПредставлениеОперанда = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
			ЭтоФункция = ОписаниеЭлемента.Значение;
			
			ПутьКДанным = ОчиститьКвадратныеСкобки(ПредставлениеОперанда);
			Реквизит = НайтиРеквизит(Форма, ИмяСпискаПолей, ПутьКДанным, КоллекцияПолей.ПолучитьЭлементы(), Истина);
			Если Реквизит <> Неопределено  Тогда
				Если ЭтоФункция <> Реквизит.ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				Операнд = ОчиститьКвадратныеСкобки(Реквизит.ПутьКДанным);
				Если СкобкиИдентификаторов Тогда
					Операнд = ОбернутьВКвадратныеСкобки(Операнд);
				КонецЕсли;
				ЗаменяемыеЭлементы.Вставить(ОписаниеЭлемента.Ключ, Операнд);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	ЗаменитьЭлементыФормулы(Выражение, ЭлементыФормулы, ЗаменяемыеЭлементы, ЭкранироватьНеизвестныеФункции);
	Возврат Выражение;
	
КонецФункции

Функция ПредставлениеФормулы(Форма, Формула) Экспорт
	
	ЭлементыФормулы = ЭлементыФормулы(Формула);
	Выражение = Формула;
	ЗаменяемыеЭлементы = Новый Соответствие;
	
	Для Каждого Элемент Из Форма.ПодключенныеСпискиПолей Цикл
		ИмяСпискаПолей = Элемент.ИмяСпискаПолей;
		КоллекцияПолей = Форма[ИмяСпискаПолей];
		СкобкиПредставлений = Элемент.СкобкиПредставлений;
		
		Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
			Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
			ЭтоФункция = ОписаниеЭлемента.Значение;
			
			ПутьКДанным = ОчиститьКвадратныеСкобки(Операнд);
			Если СтрНайти(ПутьКДанным, "[") Или СтрНайти(ПутьКДанным, "]") Тогда
				Продолжить;
			КонецЕсли;
			
			ПутьКДанным = Строка(Новый ПолеКомпоновкиДанных(ПутьКДанным));
			
			Реквизит = НайтиРеквизит(Форма, ИмяСпискаПолей, ПутьКДанным, КоллекцияПолей.ПолучитьЭлементы(), Ложь);
			Если Реквизит <> Неопределено Тогда
				Если ЭтоФункция <> Реквизит.ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				ПредставлениеОперанда = Реквизит.ПредставлениеПутиКДанным;
				Если СкобкиПредставлений Тогда
					ПредставлениеОперанда = ОбернутьВКвадратныеСкобки(Реквизит.ПредставлениеПутиКДанным);
				КонецЕсли;
				ЗаменяемыеЭлементы.Вставить(ОписаниеЭлемента.Ключ, ПредставлениеОперанда);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	ЗаменитьЭлементыФормулы(Выражение, ЭлементыФормулы, ЗаменяемыеЭлементы, Ложь);
	Возврат Выражение;
	
КонецФункции

Функция ПредставлениеВыражения(Знач Выражение, СпискиПолей) Экспорт
	
	ЭлементыФормулы = ЭлементыФормулы(Выражение);
	Результат = Выражение;
	ЗаменяемыеЭлементы  = Новый Соответствие;
	
	Для Каждого НастройкиСписка Из СпискиПолей Цикл
		КоллекцияПолей = НастройкиСписка.КоллекцияПолей;
		ИсточникиДоступныхПолей = НастройкиСписка.ИсточникиДоступныхПолей;
		Если КоллекцияПолей = Неопределено Тогда
			КоллекцияПолей = НоваяКоллекцияПолей();
			ЗаполнитьСписокДоступныхРеквизитов(КоллекцияПолей, ИсточникиДоступныхПолей, , НастройкиСписка);
		КонецЕсли;
		
		Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
			Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
			ЭтоФункция = ОписаниеЭлемента.Значение;
			
			ПутьКДанным = ОчиститьКвадратныеСкобки(Операнд);
			Реквизит = НайтиПоле(ПутьКДанным, ПодчиненныеЭлементы(КоллекцияПолей), Ложь, ИсточникиДоступныхПолей, НастройкиСписка);
			Если Реквизит <> Неопределено Тогда
				Если ЭтоФункция <> Реквизит.ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				ПредставлениеОперанда = Реквизит.ПредставлениеПутиКДанным;
				Если НастройкиСписка.СкобкиПредставлений Тогда
					ПредставлениеОперанда = ОбернутьВКвадратныеСкобки(Реквизит.ПредставлениеПутиКДанным);
				КонецЕсли;
				ЗаменяемыеЭлементы.Вставить(ОписаниеЭлемента.Ключ, ПредставлениеОперанда);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;

	ЗаменитьЭлементыФормулы(Результат, ЭлементыФормулы, ЗаменяемыеЭлементы);
	Возврат Результат;
	
КонецФункции

Функция ФорматПоля(ПутьКДанным, АдресСхемы)
	
	Если Не ЗначениеЗаполнено(АдресСхемы) Тогда
		Возврат "";
	КонецЕсли;
	
	СхемаКомпоновкиДанных = ПолучитьИзВременногоХранилища(АдресСхемы); // СхемаКомпоновкиДанных
	
	Поле = СхемаКомпоновкиДанных.НаборыДанных[0].Поля.Найти(ПутьКДанным);
	Если ТипЗнч(Поле) <> Тип("ПолеНабораДанныхСхемыКомпоновкиДанных") Тогда
		Если ПутьКДанным = "Дата" Тогда
			Возврат "ДЛФ=D;";
		Иначе
			Возврат "";
		КонецЕсли;
	КонецЕсли;
	
	ЗначениеПараметра = Поле.Оформление.НайтиЗначениеПараметра(Новый ПараметрКомпоновкиДанных("Формат"));
	Если ЗначениеПараметра <> Неопределено Тогда
		Возврат ЗначениеПараметра.Значение;
	КонецЕсли;

	Возврат "";
	
КонецФункции

Функция ВыражениеДляПроверки(Форма, ПредставлениеФормулы, ИмяСпискаОперандов) Экспорт
	
	ЭлементыФормулы = ЭлементыФормулы(ПредставлениеФормулы);
	Выражение = ПредставлениеФормулы;
	ЗаменяемыеЭлементы = Новый Соответствие;
	
	Для Каждого Элемент Из Форма.ПодключенныеСпискиПолей Цикл
		ИмяСпискаПолей = Элемент.ИмяСпискаПолей;
		КоллекцияПолей = Форма[ИмяСпискаПолей];
		СкобкиИдентификаторов = Элемент.СкобкиИдентификаторов;
		
		Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
			ПредставлениеОперанда = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
			ЭтоФункция = ОписаниеЭлемента.Значение;
			
			ПутьКДанным = ОчиститьКвадратныеСкобки(ПредставлениеОперанда);
			Реквизит = НайтиРеквизит(Форма, ИмяСпискаПолей, ПутьКДанным, КоллекцияПолей.ПолучитьЭлементы(), Истина);
			Если Реквизит <> Неопределено  Тогда
				Если ЭтоФункция <> Реквизит.ЭтоФункция Тогда
					Продолжить;
				КонецЕсли;
				
				Если ИмяСпискаОперандов = ИмяСпискаПолей Тогда
					Операнд = Реквизит.Тип.ПривестиЗначение(1);
					Если ТипЗнч(Операнд) = Тип("Строка") Тогда
						Операнд = """" + Операнд + """";
					КонецЕсли;
					Если ТипЗнч(Операнд) = Тип("Булево") Тогда
						Операнд = Формат(Операнд, "БЛ=Ложь; БИ=Истина"); // Должно быть на языке конфигурации.
					КонецЕсли;
					Если ТипЗнч(Операнд) = Тип("Дата") Тогда
						Операнд = "'" + Формат(ТекущаяДатаСеанса(), "ДФ=ггггММддЧЧмм") +  "'"; // Для использования в выражении Вычислить().
					КонецЕсли;
					Если ОбщегоНазначения.ЭтоСсылка(ТипЗнч(Операнд)) Тогда
						Операнд = "1";
					КонецЕсли;
				Иначе
					Операнд = ОчиститьКвадратныеСкобки(Реквизит.ПутьКДанным);
					Если СкобкиИдентификаторов Тогда
						Операнд = ОбернутьВКвадратныеСкобки(Операнд);
					КонецЕсли;
				КонецЕсли;
				
				ЗаменяемыеЭлементы.Вставить(ОписаниеЭлемента.Ключ, Операнд);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	ЗаменитьЭлементыФормулы(Выражение, ЭлементыФормулы, ЗаменяемыеЭлементы);
	Выражение = ФорматироватьЧисла(Выражение);
	
	Возврат Выражение;
	
КонецФункции

Процедура ЗаменитьЭлементыФормулы(Выражение, ЭлементыФормулы, Значения, ЭкранироватьНеизвестныеФункции = Истина)
	
	Для Каждого ОписаниеЭлемента Из ЭлементыФормулы.ОперандыИФункции Цикл
		Операнд = ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ];
		ЭтоФункция = ОписаниеЭлемента.Значение;
		Значение = Значения[ОписаниеЭлемента.Ключ];
		Если Значение = Неопределено Тогда
			Если ЭтоФункция И ЭкранироватьНеизвестныеФункции
				И Не СтрЗаканчиваетсяНа(Операнд, СуффиксОтключеннойФункции()) Тогда
				Значение = Операнд + СуффиксОтключеннойФункции();
			Иначе
				Значение = Операнд;
			КонецЕсли;
		КонецЕсли;
		
		ЭлементыФормулы.ВсеЭлементы[ОписаниеЭлемента.Ключ] = Значение;
	КонецЦикла;
	
	Выражение = СтрСоединить(ЭлементыФормулы.ВсеЭлементы);
	
КонецПроцедуры

Функция СуффиксОтключеннойФункции()
	
	Возврат "__";
	
КонецФункции

Функция ОчиститьКвадратныеСкобки(Строка)
	
	Если СтрНачинаетсяС(Строка, "[") И СтрЗаканчиваетсяНа(Строка, "]") Тогда
		Возврат Сред(Строка, 2, СтрДлина(Строка) - 2);
	КонецЕсли;
	
	Возврат Строка;
	
КонецФункции

Функция ОбернутьВКвадратныеСкобки(Строка)
	
	Возврат "[" + Строка + "]";
	
КонецФункции

Функция НайтиРеквизит(Форма, ИмяСписка, ПутьКДанным, КоллекцияРеквизитов, ИскатьПоПредставлению)
	
	ИмяПоляПоиска = "ПутьКДанным";
	Если ИскатьПоПредставлению Тогда
		ИмяПоляПоиска = "ПредставлениеПутиКДанным";
	КонецЕсли;
	
	Владелец = Неопределено;
	Папки = Новый Массив;
	
	Для Каждого Реквизит Из КоллекцияРеквизитов Цикл
		Если НРег(Реквизит[ИмяПоляПоиска]) = НРег(ПутьКДанным) Тогда
			Возврат Реквизит;
		КонецЕсли;
		Если Реквизит.Папка Тогда
			Папки.Добавить(Реквизит);
		Иначе
			Если СтрНачинаетсяС(НРег(ПутьКДанным), НРег(Реквизит[ИмяПоляПоиска]) + ".") Тогда
				Владелец = Реквизит;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если Владелец <> Неопределено Тогда
		РазвернутьРеквизит(Владелец.ПолучитьИдентификатор(), ИмяСписка, Форма);
		Возврат НайтиРеквизит(Форма, ИмяСписка, ПутьКДанным, Владелец.ПолучитьЭлементы(), ИскатьПоПредставлению);
	КонецЕсли;
	
	Для Каждого Папка Из Папки Цикл
		РазвернутьРеквизит(Папка.ПолучитьИдентификатор(), ИмяСписка, Форма);
		Реквизит = НайтиРеквизит(Форма, ИмяСписка, ПутьКДанным, Папка.ПолучитьЭлементы(), ИскатьПоПредставлению);
		
		Если Реквизит <> Неопределено Тогда
			Возврат Реквизит;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Неопределено;
	
КонецФункции

Функция НайтиПоле(ПутьКДанным, КоллекцияРеквизитов, ИскатьПоПредставлению, ИсточникиДоступныхПолей, НастройкиСписка)
	
	ИмяПоляПоиска = "ПутьКДанным";
	Если ИскатьПоПредставлению Тогда
		ИмяПоляПоиска = "ПредставлениеПутиКДанным";
	КонецЕсли;
	
	Владелец = Неопределено;
	Папки = Новый Массив;
	
	Для Каждого Реквизит Из КоллекцияРеквизитов Цикл
		Если НРег(Реквизит[ИмяПоляПоиска]) = НРег(ПутьКДанным) Тогда
			Возврат Реквизит;
		КонецЕсли;
		Если Реквизит.Папка Тогда
			Папки.Добавить(Реквизит);
		Иначе
			Если СтрНачинаетсяС(НРег(ПутьКДанным), НРег(Реквизит[ИмяПоляПоиска]) + ".") Тогда
				Владелец = Реквизит;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если Владелец <> Неопределено Тогда
		РазвернутьПоле(Владелец, ИсточникиДоступныхПолей, НастройкиСписка);
		Возврат НайтиПоле(ПутьКДанным, ПодчиненныеЭлементы(Владелец), ИскатьПоПредставлению, ИсточникиДоступныхПолей, НастройкиСписка);
	КонецЕсли;
	
	Для Каждого Папка Из Папки Цикл
		РазвернутьПоле(Папка, ИсточникиДоступныхПолей, НастройкиСписка);
		Реквизит = НайтиПоле(ПутьКДанным, ПодчиненныеЭлементы(Папка), ИскатьПоПредставлению, ИсточникиДоступныхПолей, НастройкиСписка);
		
		Если Реквизит <> Неопределено Тогда
			Возврат Реквизит;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Неопределено;
	
КонецФункции

#КонецОбласти

Функция РеквизитыПодключаемогоСписка()
	
	Результат = Новый Структура;
	
	Результат.Вставить("Имя", Новый ОписаниеТипов("Строка"));
	Результат.Вставить("Заголовок", Новый ОписаниеТипов("Строка"));
	Результат.Вставить("Поле", Новый ОписаниеТипов());
	Результат.Вставить("ПутьКДанным", Новый ОписаниеТипов("Строка"));
	Результат.Вставить("ПредставлениеПутиКДанным", Новый ОписаниеТипов);
	Результат.Вставить("Тип", Новый ОписаниеТипов("ОписаниеТипов"));
	Результат.Вставить("Картинка", Новый ОписаниеТипов("Картинка"));
	Результат.Вставить("Папка", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("Таблица", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("СвойНаборПолей", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("Отступ", Новый ОписаниеТипов("Строка"));
	Результат.Вставить("СоответствуетОтбору", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("ПодчиненныйЭлементСоответствуетОтбору", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("ЭтоГруппа", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("ЭтоФункция", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("Скрытый", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("ВыражениеДляВставки", Новый ОписаниеТипов("Строка"));
	
	Возврат Результат;
	
КонецФункции

Функция РеквизитыСпискаИсточниковДоступныхПолей()
	
	Результат = Новый Структура;
	
	Результат.Вставить("ИсточникДанных", Новый ОписаниеТипов("Строка"));
	Результат.Вставить("КоллекцияПолей", Новый ОписаниеТипов());
	Результат.Вставить("Замещать", Новый ОписаниеТипов("Булево"));
	Результат.Вставить("СхемаКомпоновкиДанных", Новый ОписаниеТипов());
	Результат.Вставить("ИдентификаторСхемыКомпоновкиДанных", Новый ОписаниеТипов("Строка"));
	
	Возврат Результат;
	
КонецФункции

Функция НоваяКоллекцияПолей()
	
	Результат = Новый ДеревоЗначений();
	Для Каждого ОписаниеРеквизита Из РеквизитыПодключаемогоСписка() Цикл
		ИмяРеквизита = ОписаниеРеквизита.Ключ;
		ТипРеквизита = ОписаниеРеквизита.Значение;
		Результат.Колонки.Добавить(ИмяРеквизита, ТипРеквизита);
	КонецЦикла;	
	
	Возврат Результат;
	
КонецФункции

Функция КартинкаТипа(ОписаниеТипов)
	
	Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипНеопределено");
	Если ОписаниеТипов.Типы().Количество() = 1 Тогда
		Тип = ОписаниеТипов.Типы()[0];
		Если Тип = Тип("Число") Тогда
			Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипЧисло");
		ИначеЕсли Тип = Тип("Дата") Тогда
			Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипДата");
		ИначеЕсли Тип = Тип("Булево") Тогда
			Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипБулево");
		ИначеЕсли Тип = Тип("Строка") Тогда
			Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипСтрока");
		ИначеЕсли ОбщегоНазначения.ЭтоСсылка(Тип) Тогда
			Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипСсылка");
		ИначеЕсли Тип = Тип("УникальныйИдентификатор") Тогда
			Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипИдентификатор");
		КонецЕсли;
	ИначеЕсли ОписаниеТипов.Типы().Количество() > 1 Тогда
		Картинка = КонструкторФормулПовтИсп.КартинкаПоИмени("ТипСоставнойОсновной");
	КонецЕсли;
	
	Возврат Картинка;
	
КонецФункции

Функция СписокОператоров(ГруппыОператоров = Неопределено) Экспорт
	
	СписокОператоров =  ДеревоПолей();
	
	Если ГруппыОператоров = Неопределено Тогда
		ГруппыОператоров = "ЛогическиеОператорыИКонстанты,
		|ЧисловыеФункции, СтроковыеФункции, ПрочиеФункции";
	ИначеЕсли ГруппыОператоров = "ВсеОператорыСКД" Тогда
		ГруппыОператоров = "ОперацииНадСтрокамиСКД, РаботаСДатамиСКД, ОперацииСравненияСКД,
		|ЛогическиеОперацииСКД, АгрегатныеФункцииСКД, ПрочиеФункцииСКД";
	КонецЕсли;
	
	Для Каждого Элемент Из Новый Структура(ГруппыОператоров) Цикл
		ИмяГруппы = Элемент.Ключ;
		Если ИмяГруппы = "ЛогическиеОператорыИКонстанты" Тогда
			ДобавитьГруппуОператоровЛогическиеОператорыИКонстанты(СписокОператоров);
		ИначеЕсли ИмяГруппы = "ЧисловыеФункции" Тогда
			ДобавитьГруппуОператоровЧисловыеФункции(СписокОператоров);
		ИначеЕсли ИмяГруппы = "СтроковыеФункции" Тогда
			ДобавитьГруппуОператоровСтроковыеФункции(СписокОператоров);
		ИначеЕсли ИмяГруппы = "ПрочиеФункции" Тогда
			ДобавитьГруппуОператоровПрочиеФункции(СписокОператоров);
		ИначеЕсли ИмяГруппы = "ОперацииНадСтрокамиСКД" Тогда
			ДобавитьГруппуОператоровОперацииНадСтроками(СписокОператоров);
		ИначеЕсли ИмяГруппы = "РаботаСДатамиСКД" Тогда
			ДобавитьГруппуОператоровРаботаСДатами(СписокОператоров);
		ИначеЕсли ИмяГруппы = "ОперацииСравненияСКД" Тогда
			ДобавитьГруппуОператоровОперацииСравнения(СписокОператоров);
		ИначеЕсли ИмяГруппы = "ЛогическиеОперацииСКД" Тогда
			ДобавитьГруппуОператоровЛогическиеОперации(СписокОператоров);
		ИначеЕсли ИмяГруппы = "АгрегатныеФункцииСКД" Тогда
			ДобавитьГруппуОператоровАгрегатныеФункции(СписокОператоров);
		ИначеЕсли ИмяГруппы = "ПрочиеФункцииСКД" Тогда
			ДобавитьГруппуОператоровПрочиеФункцииСКД(СписокОператоров);
		КонецЕсли;
	КонецЦикла;	
	
	Возврат СписокОператоров;
	
КонецФункции

Процедура ДобавитьГруппуОператоровЛогическиеОператорыИКонстанты(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ЛогическиеОператорыИКонстанты";
	Группа.Представление = НСтр("ru = 'Логические операторы и константы'");
	Группа.Порядок = 3;
	
	Тип = Новый ОписаниеТипов("Булево");
	
	ДобавитьОператорВГруппу(Группа, "И", НСтр("ru = 'И'"), Тип);
	ДобавитьОператорВГруппу(Группа, "Или", НСтр("ru = 'Или'"), Тип);
	ДобавитьОператорВГруппу(Группа, "Не", НСтр("ru = 'Не'"), Тип);
	ДобавитьОператорВГруппу(Группа, "Истина", НСтр("ru = 'Истина'"), Тип);
	ДобавитьОператорВГруппу(Группа, "Ложь", НСтр("ru = 'Ложь'"), Тип);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровЧисловыеФункции(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ЧисловыеФункции";
	Группа.Представление = НСтр("ru = 'Числовые функции'");
	Группа.Порядок = 4;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	Тип = Новый ОписаниеТипов("Число");
	
	ДобавитьОператорВГруппу(Группа, "Макс", НСтр("ru = 'Максимум'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "Мин", НСтр("ru = 'Минимум'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "Окр", НСтр("ru = 'Округлить'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "Цел", НСтр("ru = 'Целая часть'"), Тип, Истина);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровСтроковыеФункции(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "СтроковыеФункции";
	Группа.Представление = НСтр("ru = 'Строковые функции'");
	Группа.Порядок = 5;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	Тип = Новый ОписаниеТипов("Строка");
	
	// В НСтр переводимые на другие языки идентификаторы.
	
	ДобавитьОператорВГруппу(Группа, "Строка", НСтр("ru = 'Преобразовать в строку'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ВРег", НСтр("ru = 'Все прописные'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "НРег", НСтр("ru = 'Все строчные'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ТРег", НСтр("ru = 'Каждое слово с прописной'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "Лев", НСтр("ru = 'Символы слева'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "Прав", НСтр("ru = 'Символы справа'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СокрЛ", НСтр("ru = 'Убрать пробелы слева'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СокрЛП", НСтр("ru = 'Убрать пробелы слева и справа'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СокрП", НСтр("ru = 'Убрать пробелы справа'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СтрЗаменить", НСтр("ru = 'Заменить символы в строке'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СтрДлина", НСтр("ru = 'Длина строки'"), Новый ОписаниеТипов("Число"), Истина);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровПрочиеФункции(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ПрочиеФункции";
	Группа.Представление = НСтр("ru = 'Прочие функции'");
	Группа.Порядок = 6;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	ДобавитьОператорВГруппу(Группа, "?", НСтр("ru = 'Условие'"), Новый ОписаниеТипов("Булево"), Истина);
	ДобавитьОператорВГруппу(Группа, "ЗначениеЗаполнено", НСтр("ru = 'Значение заполнено'"), Новый ОписаниеТипов("Булево"), Истина);
	ДобавитьОператорВГруппу(Группа, "Формат", НСтр("ru = 'Формат'"), Новый ОписаниеТипов("Строка"), Истина);
	
КонецПроцедуры

Процедура ДобавитьОператорВГруппу(Группа, Идентификатор, Знач Представление, Тип = Неопределено, ЭтоФункция = Ложь, Скрытый = Ложь)
	
	Оператор = Группа.Строки.Добавить();
	Оператор.Идентификатор = Идентификатор;
	Оператор.Представление = ПредставлениеОператора(Представление);
	Оператор.ТипЗначения = Тип;
	Оператор.Картинка = БиблиотекаКартинок.Пустая;
	Оператор.ЭтоФункция = ЭтоФункция;
	Оператор.Скрытый = Скрытый;

КонецПроцедуры

Процедура ДобавитьГруппуОператоровОперацииНадСтроками(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ОперацииНадСтроками";
	Группа.Представление = НСтр("ru = 'Операции над строками'");
	Группа.Порядок = 2;
	
	Тип = Новый ОписаниеТипов("Строка");
	
	ДобавитьОператорВГруппу(Группа, "ПОДОБНО", НСтр("ru = 'ПОДОБНО'"), Тип);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровРаботаСДатами(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "РаботаСДатамиСКД";
	Группа.Представление = НСтр("ru = 'Работа с датами'");
	Группа.Порядок = 2;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	Тип = Новый ОписаниеТипов("Число");
	
	ДобавитьОператорВГруппу(Группа, "ГОД", НСтр("ru = 'ГОД'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "МЕСЯЦ", НСтр("ru = 'МЕСЯЦ'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ЧИСЛО", НСтр("ru = 'ЧИСЛО'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ДЕНЬГОДА", НСтр("ru = 'День года'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ДЕНЬ", НСтр("ru = 'ДЕНЬ'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "НЕДЕЛЯ", НСтр("ru = 'НЕДЕЛЯ'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ДЕНЬНЕДЕЛИ", НСтр("ru = 'День недели'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ЧАС", НСтр("ru = 'ЧАС'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "МИНУТА", НСтр("ru = 'МИНУТА'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СЕКУНДА", НСтр("ru = 'СЕКУНДА'"), Тип, Истина);

	ДобавитьОператорВГруппу(Группа, "НАЧАЛОПЕРИОДА", НСтр("ru = 'Начало периода'"), Новый ОписаниеТипов, Истина);
	ДобавитьОператорВГруппу(Группа, "КОНЕЦПЕРИОДА", НСтр("ru = 'Конец периода'"), Новый ОписаниеТипов, Истина);
	ДобавитьОператорВГруппу(Группа, "ДОБАВИТЬКДАТЕ", НСтр("ru = 'Добавить к дате'"), Новый ОписаниеТипов, Истина);
	
	ДобавитьОператорВГруппу(Группа, "РАЗНОСТЬДАТ", НСтр("ru = 'Разность дат'"), Тип, Истина);
	
	ДобавитьОператорВГруппу(Группа, "ТЕКУЩАЯДАТА", НСтр("ru = 'Текущая дата'"), Новый ОписаниеТипов, Истина);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровОперацииСравнения(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ОперацииСравнения";
	Группа.Представление = НСтр("ru = 'Операции сравнения'");
	Группа.Порядок = 3;
	
	Тип = Новый ОписаниеТипов("Булево");
	
	ДобавитьОператорВГруппу(Группа, "В", НСтр("ru = 'В'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "ЗначениеЗаполнено", НСтр("ru = 'Значение заполнено'"), Тип, Истина);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровЛогическиеОперации(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ЛогическиеОперации";
	Группа.Представление = НСтр("ru = 'Логические операции'");
	Группа.Порядок = 4;
	
	Тип = Новый ОписаниеТипов("Булево");
	
	ДобавитьОператорВГруппу(Группа, "НЕ", НСтр("ru = 'НЕ'"), Тип);
	ДобавитьОператорВГруппу(Группа, "И", НСтр("ru = 'И'"), Тип);
	ДобавитьОператорВГруппу(Группа, "ИЛИ", НСтр("ru = 'ИЛИ'"), Тип);
	
	Оператор = Группа.Строки.Добавить();
	Оператор.Идентификатор = "ВЫБОРКОГДАТОГДАИНАЧЕКОНЕЦ";
	Оператор.Представление = СтрШаблон(
		НСтр("ru = '%1 %2 ... %3 ...'"),
		ПредставлениеОператора(НСтр("ru = 'ВЫБОР'")),
		ПредставлениеОператора(НСтр("ru = 'КОГДА'")),
		ПредставлениеОператора(НСтр("ru = 'ТОГДА'")));
	Оператор.Картинка = БиблиотекаКартинок.Пустая;
	Оператор.ВыражениеДляВставки = СтрШаблон(НСтр(
		"ru = '%1
		|	%2 <%6> %3 <%6>
		|	%4 <%6>
		|%5'"),
		ПредставлениеОператора(НСтр("ru = 'ВЫБОР'")),
		ПредставлениеОператора(НСтр("ru = 'КОГДА'")),
		ПредставлениеОператора(НСтр("ru = 'ТОГДА'")),
		ПредставлениеОператора(НСтр("ru = 'ИНАЧЕ'")),
		ПредставлениеОператора(НСтр("ru = 'КОНЕЦ'")),
		НСтр("ru = 'Выражение'"));
	
	ДобавитьОператорВГруппу(Группа, "ВЫБОР", НСтр("ru = 'ВЫБОР'"), , , Истина); // @query-part
	ДобавитьОператорВГруппу(Группа, "КОГДА", НСтр("ru = 'КОГДА'"), , , Истина);
	ДобавитьОператорВГруппу(Группа, "ТОГДА", НСтр("ru = 'ТОГДА'"), , , Истина);
	ДобавитьОператорВГруппу(Группа, "ИНАЧЕ", НСтр("ru = 'ИНАЧЕ'"), , , Истина);
	ДобавитьОператорВГруппу(Группа, "КОНЕЦ", НСтр("ru = 'КОНЕЦ'"), , , Истина);
	ДобавитьОператорВГруппу(Группа, "ИСТИНА", НСтр("ru = 'ИСТИНА'"), , , Истина);
	ДобавитьОператорВГруппу(Группа, "ЛОЖЬ", НСтр("ru = 'ЛОЖЬ'"), , , Истина);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровАгрегатныеФункции(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "АгрегатныеФункции";
	Группа.Представление = НСтр("ru = 'Агрегатные функции'");
	Группа.Порядок = 5;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	Тип = Новый ОписаниеТипов("Число");
	
	ДобавитьОператорВГруппу(Группа, "СУММА", НСтр("ru = 'СУММА'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "КОЛИЧЕСТВО", НСтр("ru = 'КОЛИЧЕСТВО'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "МАКСИМУМ", НСтр("ru = 'МАКСИМУМ'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "МИНИМУМ", НСтр("ru = 'МИНИМУМ'"), Тип, Истина);
	ДобавитьОператорВГруппу(Группа, "СРЕДНЕЕ", НСтр("ru = 'СРЕДНЕЕ'"), Тип, Истина);
	
КонецПроцедуры

Процедура ДобавитьГруппуОператоровПрочиеФункцииСКД(СписокОператоров)
	
	Группа = СписокОператоров.Строки.Добавить();
	Группа.Идентификатор = "ПрочиеФункции";
	Группа.Представление = НСтр("ru = 'Прочие функции'");
	Группа.Порядок = 6;
	Группа.Картинка = БиблиотекаКартинок.ТипФункция;
	
	ДобавитьОператорВГруппу(Группа, "СТРОКА", НСтр("ru = 'СТРОКА'"), Новый ОписаниеТипов("Строка"), Истина);
	ДобавитьОператорВГруппу(Группа, "ЗНАЧЕНИЕ", НСтр("ru = 'ЗНАЧЕНИЕ'"), Новый ОписаниеТипов, Истина);
	
КонецПроцедуры

Функция ИмяРеквизитаСтрокиПоискаСпискаПолей(ИмяСпискаПолей)
	
	Возврат "СтрокаПоиска" + ИмяСпискаПолей;
	
КонецФункции

Функция ИмяРеквизитаСпискаПолей(ИмяСтрокиПоискаСпискаПолей)
	
	Возврат СтрЗаменить(ИмяСтрокиПоискаСпискаПолей, "СтрокаПоиска", "");
	
КонецФункции

Функция ИмяОсновногоИсточникаДанных(ИсточникиДоступныхПолей)
	
	Если ИсточникиДоступныхПолей.Количество() > 0 Тогда
		Возврат ИсточникиДоступныхПолей[0].ИсточникДанных;
	КонецЕсли;
	
	Возврат "";
	
КонецФункции

Функция ФорматироватьЧисла(Строка, РазделительДробнойЧасти = ".")
	
	Результат = "";
	Число = "";
	ЕстьРазделительВЧисле = Ложь;
	ПредыдущийСимвол = "";
	
	ДлинаСтроки = СтрДлина(Строка);
	Для Индекс = 1 По ДлинаСтроки Цикл
		Если Индекс < ДлинаСтроки Тогда
			СледующийСимвол = Сред(Строка, Индекс + 1, 1);
		Иначе
			СледующийСимвол = "";
		КонецЕсли;
		Символ = Сред(Строка, Индекс, 1);
		
		ПредыдущийСимволЭтоРазделитель = ПредыдущийСимвол = "" Или СтрНайти("()[]/*-+%=<>, " + Символы.Таб + Символы.ПС, ПредыдущийСимвол) > 0;
		
		Если ЭтоЦифра(Символ) И (ПредыдущийСимволЭтоРазделитель Или ЭтоЦифра(ПредыдущийСимвол) И ЗначениеЗаполнено(Число)) Тогда
			Число = Число + Символ;
		ИначеЕсли Не ЕстьРазделительВЧисле И (Символ = "," Или Символ = ".") И ЭтоЦифра(СледующийСимвол)
			И (ЭтоЦифра(ПредыдущийСимвол) Или ПредыдущийСимволЭтоРазделитель) И ЗначениеЗаполнено(Число) Тогда
			Число = Число + РазделительДробнойЧасти;
			ЕстьРазделительВЧисле = Истина;
		Иначе
			Результат = Результат + Число + Символ;
			Число = "";
			ЕстьРазделительВЧисле = Ложь;
		КонецЕсли;
		
		ПредыдущийСимвол = Символ;
		Символ = "";
	КонецЦикла;
	
	Результат = Результат + Число + Символ;
	Возврат Результат;
	
КонецФункции

Функция ЭтоЦифра(Символ)
	
	Возврат СтрНайти("1234567890", Символ) > 0;
	
КонецФункции

Функция ИмяПоля(Поле)
	
	ИмяПоля = "";
	Строка = Строка(Поле);
	ОткрывающихСкобок = 0;
	
	Для Индекс = -СтрДлина(Строка) По -1 Цикл
		Позиция = -Индекс;
		Символ = Сред(Строка, Позиция, 1);
		
		Если Символ = "]" Тогда
			ОткрывающихСкобок = ОткрывающихСкобок + 1;
		КонецЕсли;
		
		Если Символ = "[" Тогда
			ОткрывающихСкобок = ОткрывающихСкобок - 1;
		КонецЕсли;
		
		Если Символ = "." И ОткрывающихСкобок = 0 Тогда
			Прервать;
		Иначе
			ИмяПоля = Символ + ИмяПоля;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ИмяПоля;
	
КонецФункции

Функция ЕстьПодчиненныеЭлементы(Знач ОписаниеПоля)
	
	Если ОписаниеПоля.Папка Или ОписаниеПоля.Таблица Тогда
		Возврат Истина;
	КонецЕсли;
	
	Для Каждого Тип Из ОписаниеПоля.Тип.Типы() Цикл
		Если ОбщегоНазначения.ЭтоСсылка(Тип) 
			Или Тип = Тип("Дата") И ОписаниеПоля.Элементы.Количество() > 0 Тогда
			Возврат Истина;
		КонецЕсли; 
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

Процедура УбратьПризнакОтбора(Коллекция)
	Для Каждого СтрокаКоллекции Из Коллекция.Строки Цикл
		СтрокаКоллекции.СоответствуетОтбору = Ложь;
		СтрокаКоллекции.ПодчиненныйЭлементСоответствуетОтбору = Ложь;
		УбратьПризнакОтбора(СтрокаКоллекции);
	КонецЦикла;
КонецПроцедуры

Функция ДоступныеПоляВКонтейнерСКД(ДоступныеПоля)
	ДеревоПолей = ДеревоПолей();
	ЗаполнитьДеревоПоДоступнымПолям(ДеревоПолей, ДоступныеПоля);
	Возврат СхемаКомпоновкиДанныхИзДереваЗначений(ДеревоПолей);
КонецФункции

Функция ПредставлениеОператора(Знач Оператор)
	
	Возврат СтрЗаменить(ТРег(Оператор), " ", "")
	
КонецФункции

#КонецОбласти